我希望能够加载整个应用程序,以便找到给定类的后代。
例如,鉴于我定义了以下类:
# 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]
我将如何做到这一点?
答案 0 :(得分:35)
嗯,经过一些挖掘,它实际上非常简单。只需要运行以下内容。
Rails.application.eager_load!
答案 1 :(得分:8)
来自Configuring Rails Applications
修改强>
要手动加载,您应该可以执行以下操作:
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回答不会急于将文件存储在Engine
或gems
文件夹中的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)