在Rails初始化上加载子索引

时间:2011-11-29 05:23:44

标签: ruby-on-rails ruby-on-rails-3

我遇到了让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

它完成了工作,但我觉得这样做很脏。任何想法都会非常感激。

3 个答案:

答案 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