Rails迫使模型急切负载

时间:2013-11-07 15:29:51

标签: ruby-on-rails ruby

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

例如,鉴于我定义了以下类:

# app/models/foo_class.rb
class FooClass < MySpecialBaseClass
  # pasta code
end

找不到:

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

直到我调用const:

irb> FooClass

然后返回:

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

=> [FooClass]

我将如何做到这一点?

4 个答案:

答案 0 :(得分:35)

嗯,经过一些挖掘,它实际上非常简单。只需要运行以下内容。

Rails.application.eager_load!

答案 1 :(得分:8)

来自Configuring Rails Applications

  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目录中的每个文件夹。
  4. 修改

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

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

答案 2 :(得分:5)

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

Rails.configuration.eager_load_namespaces.each(&:eager_load!)

这两种方法之间的显着区别是OP回答不会急于将文件存储在Enginegems文件夹中的vendor个应用程序目录中。 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

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

答案 3 :(得分:2)

使用 Rails 6 Zetiwerk成为默认的代码加载器。

尝试此操作以加载:

Zeitwerk::Loader.eager_load_all