【问题标题】:Rails class loading skips namespaced class when another class of same name in root namespace is loaded当加载根命名空间中的另一个同名类时,Rails 类加载会跳过命名空间类
【发布时间】:2012-11-05 16:19:56
【问题描述】:

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

两个演示者都继承自 ::DocumentPresenter

控制器在没有指定命名空间的情况下访问它们各自的演示者,例如:

class Guest::DocumentsController < ActionController::Base
    def show
        DocumentPresenter.new(find_document)
    end
end

这通常在同一个命名空间内调用presenter。但是有时在开发环境中我看到 base ::DocumentPresenter 正在被使用。

我怀疑原因是基础 ::DocumentPresenter 已经加载,因此 Rails 类自动加载不会费心进一步查看。有可能是这种情况吗?生产环境也可以吗?

我能想到两种解决方案:

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

有没有更好的解决方案?

【问题讨论】:

  • 如果你在Guest::DocumentsController 中使用show 方法,则只能与Guest::DocumentPresenter 一起使用,那么在调用new 方法时指定命名空间是最简单的。
  • @Deefour 哈哈是的,我忘记了最明显的一个 - 谢谢。我会等待一个完美的解决方案,这不会让我在我的源文件中添加字符。
  • AFAIK Rails 仅在 production 中预加载模型,所以这也应该在生产中发生(但我在这台 ATM 上找不到实际文档)。

标签: ruby-on-rails ruby classloader


【解决方案1】:

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

作为一种解决方案,我建议将 ::DocumentPresenter 重命名为 DocumentPresenterBase,因为这样可以在您忘记命名空间或明确要求某处时避免出现错误。

要考虑的第二个选项实际上是在所有地方使用特定的命名空间类名,但是当您不小心忘记命名某个调用时,这会出现错误。

class Guest::DocumentsController < ActionController::Base
  def show
    Guest::DocumentPresenter.new(find_document)
  end
end 

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

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

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 

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

【讨论】:

    【解决方案2】:

    我认为,如果您想保留名称,有 3 个解决方案,一个是您的第二个解决方案。

    1) 在控制器文件中明确要求适当的演示者文件

    2) 执行完整的环境类路径,如:

    class Guest::DocumentsController < ActionController::Base
        def show
            Guest::DocumentPresenter.new(find_document)
        end
    end
    

    3)在初始化目录上创建一个文件并手动执行require(最糟糕的选择:S)

    【讨论】:

      猜你喜欢
      • 2014-10-10
      • 2020-05-02
      • 2011-07-23
      • 2013-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-10
      相关资源
      最近更新 更多