为什么在 Rails 引擎中明确要求应用程序控制器?

Why explicitly require application controller in Rails engines?

我正在构建一个 Rails 引擎,我注意到如果我像这样生成一个控制器 rails g controller test 它会给我以下输出:

require_dependency "my_app/application_controller"

module MyApp
 class TestController < ApplicationController
 end
end

为什么需要引擎的应用程序控制器,module MyApp 下的嵌套应该已经消除了 ApplicationControlller 与主应用程序的歧义。

所以我对 rails 源进行了一些挖掘,找到了引入此功能的提交 (sha: 7c95be54)

Fix generators to help with ambiguous ApplicationController issue

In development mode, dependencies are loaded dynamically at runtime, using const_missing. Because of that, when one of the constants is already loaded and const_missing is not triggered, user can end up with unexpected results.

Given such file in an Engine:

module Blog
class PostsController < ApplicationController
   end
end

If you load it first, before loading any application files, it will correctly load Blog::ApplicationController, because second line will hit const_missing. However if you load ApplicationController first, the constant will be loaded already, const_missing hook will not be fired and in result PostsController will inherit from ApplicationController instead of Blog::ApplicationController.

Since it can't be fixed in AS::Dependencies, the easiest fix is to just explicitly load application controller.

正如人们可能猜到的那样,这归结为自动加载问题!所以请记住孩子们,在处理可能有歧义的代码时,请始终明确说明您导入的内容。 真正令人不安的是,引擎引入的命名空间实际上并没有提供太多隔离,假设您在引擎中引用了其他一些 non-rails class 并且包含的​​主应用程序恰好有一个常量相同的名称,同样的问题将适用。

我被指向这个 post 用于 same issue within Component-based Rails apps。在这里留下我的想法以备将来参考...

可挂载的引擎带有一个命名空间,它允许另一种方法来解决这个问题:总是用它的命名空间 显式引用每个 class,即 Blog::ApplicationController.

在您的情况下,以下代码不会出现所描述的问题(不需要显式 require)。

module Blog
  class PostsController < Blog::ApplicationController
  end
end

当然,您仍然可以 运行 解决应用程序中出现两个 namespace/class 组合的问题,但这将更加罕见且更容易发现...