我遇到了让Rails(3.1.3)在应用程序初始化时加载一些ActiveRecord子类的问题。这是我的目录结构:
- models
- class1.rb # Class1 < ActiveRecord::Base
- class1s
- subclass1.rb # Subclass1 < Class1
- subclass2.rb # Subclass2 < Class1
我正在尝试使用Class1.subclasses
,但它会一直返回[]
。将#{config.root}/app/models/class1s
添加到config.autoload_paths
没有帮助,因为这些段是延迟加载的,在我调用subclasses
之前没有任何内容引用子类,因此它们已加载。添加config.eager_load_paths
的路径似乎也不起作用,其行为基于config.cache_classes
设置,这在开发和生产中通常是不同的。
我希望能够启动rails控制台并查看:
> Class1.subclasses
=> [Subclass1, Subclass2]
现在这是我看到的行为:
> Class1.subclasses
=> []
> Subclass1
=> Subclass1
> Class1.subclasses
=> [Subclass1]
> Subclass2
=> Subclass2
> Class1.subclasses
=> [Subclass1, Subclass2]
现在我被简化为将它放在我的Class1定义的底部,以便在访问Class1类时加载所有子类:
ruby_files_pattern = File.join(Rails.application.config.root, "app", "models", "class1s", "**", "*.rb")
Dir.glob(ruby_files_pattern).each do |file|
ActiveSupport::Dependencies.require_or_load(file)
end
它完成了工作,但我觉得这样做很脏。任何想法都会非常感激。
答案 0 :(得分:2)
最简单的方法是使用(&gt; = 3.0)加载所有类:
Rails.application.eager_load!
它将从您的应用,引擎,插件加载所有类。与配置中延迟加载的结果相同。但是在这种方法中你不需要这样做只使用这种方法。
答案 1 :(得分:2)
急切加载的问题是,一旦类更改,则不再加载子类。我在我的development.rb中使用了一个constantizer,它根据每个请求的文件名对我的所有子类(e.i.子目录)进行constanti化。我把它放在lib中,因为一些测试也需要对事物进行兼容。
LIB / constantizer.rb
class Constantizer
def self.path(path, include_current_path=true, namespace_prefix='')
dirs = Dir[Rails.root.join(path, '**', '**')].select { |f| File.directory?(f) && File.basename(f) != 'concerns'}
dirs << Rails.root.join(path) if include_current_path
dirs.each do |dir|
Dir["#{dir}/*.rb"].each do |file|
(namespace_prefix + file.chomp(".rb").split("/").last.camelize).constantize
end
end
end
end
应用程序/环境/ development.rb
class ConstantizeAllSubclasses
def initialize(app)
@app = app
end
def call(env)
Constantizer.path('app/models', false)
@app.call(env)
end
end
Project::Application.configure do
# Usual config items
config.middleware.insert_after Warden::Manager, ConstantizeAllSubclasses
end
答案 2 :(得分:0)
默认情况下,在开发环境中禁用了Eager Loading。
从config/environments/development.rb
config.eager_load = true