Rails强迫模型加载

Jas*_*rip 21 ruby ruby-on-rails

我希望能够加载整个应用程序,以便我可以找到给定类的后代.

例如,给定我定义了以下类:

# app/models/foo_class.rb
class FooClass < MySpecialBaseClass
  # pasta code
end
Run Code Online (Sandbox Code Playgroud)

它不会被发现:

irb> ObjectSpace.each_object.select { |obj| obj.is_a?(Class) && obj <= MySpecialBaseClass }
=> []
Run Code Online (Sandbox Code Playgroud)

直到我调用const:

irb> FooClass
Run Code Online (Sandbox Code Playgroud)

然后它返回:

irb> ObjectSpace.each_object.select { |obj| obj.is_a?(Class) && obj <= MySpecialBaseClass } 

=> [FooClass]
Run Code Online (Sandbox Code Playgroud)

我该怎么做呢?

Jas*_*rip 36

好吧,经过一些挖掘,它实际上非常简单.只需要运行以下命令.

Rails.application.eager_load!
Run Code Online (Sandbox Code Playgroud)

  • 是否可以将其放在配置文件中,以便在初始化Rails应用程序后调用它.你会把它放在哪里? (3认同)

小智 9

配置Rails应用程序

  1. config.eager_load when true Eager加载所有已注册的config.eager_load_namespaces.这包括您的应用程序,引擎,Rails框架和任何其他已注册的命名空间.
  2. config.eager_load_namespaces注册config.eager_load为true时急切加载的命名空间.列表中的所有命名空间都必须响应eager_load!方法.
  3. config.eager_load_paths接受一个路径数组,如果启用了缓存类,Rails将在启动时急切加载.默认为应用程序的app目录中的每个文件夹.

编辑:

要手动加载,您应该可以执行以下操作:

matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
  require_dependency file.sub(matcher, '\1')
end
Run Code Online (Sandbox Code Playgroud)


dem*_*mir 8

Rails 6 中Zeitwerk成为默认的代码加载器。

尝试以下进行急切加载:

Zeitwerk::Loader.eager_load_all
Run Code Online (Sandbox Code Playgroud)


wbh*_*ing 5

经过大量的试验和错误,我最近了解到Jason Waldrip的答案有些不完整。从Rails 5开始,Rails.application.eager_load!确实将加载中指定的所有目录config/application.rb。但这与Rails在生产中的实际行为不符。为此,必须改为镜像Rails的作用:

Rails.configuration.eager_load_namespaces.each(&:eager_load!)
Run Code Online (Sandbox Code Playgroud)

两种方法之间的显着区别是OP回答不会急于将这些文件加载​​到Engine位于gemsvendor文件夹中的的应用程序目录中。而Rails本身标识Engine存在子类的位置,并会确保适当地app加载了适当的子目录。

幕后花絮

Rails 5在railties-5.0.2/lib/rails/engine/configuration.rb:39运行的地方添加了渴望的加载目录

      paths.add "app",                 eager_load: true, glob: "{*,*/concerns}"
      paths.add "app/assets",          glob: "*"
      paths.add "app/controllers",     eager_load: true
      paths.add "app/channels",        eager_load: true, glob: "**/*_channel.rb"
      paths.add "app/helpers",         eager_load: true
      paths.add "app/models",          eager_load: true
      paths.add "app/mailers",         eager_load: true
Run Code Online (Sandbox Code Playgroud)

这些目录当前未包含在默认目录中 Rails.application.eager_load!