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)
小智 9
编辑:
要手动加载,您应该可以执行以下操作:
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)
在Rails 6 中,Zeitwerk成为默认的代码加载器。
尝试以下进行急切加载:
Zeitwerk::Loader.eager_load_all
Run Code Online (Sandbox Code Playgroud)
经过大量的试验和错误,我最近了解到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位于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
Run Code Online (Sandbox Code Playgroud)
这些目录当前未包含在默认目录中 Rails.application.eager_load!
| 归档时间: |
|
| 查看次数: |
11612 次 |
| 最近记录: |