当加载根命名空间中的另一个同名类时,Rails类加载会跳过命名空间类

Woj*_*ski 7 ruby ruby-on-rails classloader

我有两个名称空间,每个名称空间都有自己的控制器和演示者类: Member::DocumentsController Member::DocumentPresenter Guest::DocumentsController Guest::DocumentPresenter

两位主持人都继承自::DocumentPresenter.

控制器访问其各自的演示者而不指定名称空间,例如:

class Guest::DocumentsController < ActionController::Base
    def show
        DocumentPresenter.new(find_document)
    end
end
Run Code Online (Sandbox Code Playgroud)

这通常会在同一名称空间内调用presenter.但有时在开发环境中我看到base :: DocumentPresenter正在使用中.

我怀疑原因是base :: DocumentPresenter已经加载了,所以Rails类自动加载并不需要进一步查看.这可能是这种情况吗?它也可以在生产环境中发生吗?

我可以想到两个解决方案:

  • 将基类重命名为DocumentPresenterBase
  • 在控制器文件中明确要求适当的presenter文件

有更好的解决方案吗?

Laa*_*aas 3

您的假设是正确的 - 如果您不指定命名空间,Ruby 从当前命名空间开始并向上查找该类,并且由于命名空间类尚未自动加载,因此会找到该类并且自动加载器::DocumentPresenter不会触发。

作为解决方案,我建议重命名::DocumentPresenterDocumentPresenterBase,因为当您忘记命名空间或明确要求某处时,这可以保护您免受错误的影响。

要考虑的第二个选项实际上是在各处使用特定的命名空间类名,但是当您不小心忘记为某些调用命名空间时,这会遇到错误。

class Guest::DocumentsController < ActionController::Base
  def show
    Guest::DocumentPresenter.new(find_document)
  end
end 
Run Code Online (Sandbox Code Playgroud)

第三个选项是您的第二个选项 - 明确要求预先初始化程序中的所有类。我已经使用 Rails API 完成了此操作,Rails API 接收嵌入的模型JSON,并且当实际模型尚未加载时,Rails 倾向于为它们命名空间。

选项 3.5您可能可以欺骗自动加载器来完成繁重的工作(不过,这可能看起来更像是一种黑客攻击):

class Guest::DocumentsController < ActionController::Base

  # trigger autoload
  Guest::DocumentPresenter

  def show
    # This should refer Guest::DocumentPresenter
    DocumentPresenter.new(find_document)
  end

  def show
    # As will this
    DocumentPresenter.new(find_document)
  end
end 
Run Code Online (Sandbox Code Playgroud)

最干净的方法仍然是重命名基类。