2010-05-01 47 views
8

我想能够迭代并检查我的Rails应用程序中的所有模型。在伪代码,它看起来是这样的:如何遍历我的rails应用程序中的所有模型?

rails_env.models.each do |model| 
    associations = model.reflect_on_all_associations(:has_many) 
    ... do some stuff 
end 

我的问题是我如何检查我的Rails应用程序来获取模型(rails_env.models)的集合?

回答

2

迭代'$ RAILS_ROOT \ app \ models'中的所有文件?

例如

def find_all_models 
    # iterate over all files in folder 
    folder = File.join(RAILS_ROOT, "app", "models")  
    Dir[File.join(folder, "*")].each do |filename| 
    # remove .rb 
    model_name = File.basename(filename).sub(/.rb$/, '').capitalize 
    model = Kernel.const_get(model_name) 
    # .. do something with your model :) 
    end 
end 

这是否帮助?

9

与nathanvda的响应类似,使用camelize而不是大写来支持带下划线的模型文件,并使用String#constantize而不是Kernel.const_get。

此外,如果您在模型文件夹中保留非主动记录模型(例如用于整合搜索逻辑的搜索类),则需要检查该类是否为活动记录模型。

Dir[Rails.root.join('app/models/*.rb').to_s].each do |filename| 
    klass = File.basename(filename, '.rb').camelize.constantize 
    next unless klass.ancestors.include?(ActiveRecord::Base) 
    # do something with klass 
end 
+1

'classify'确实比'capitalize'更好,但它可能会导致问题,因为它会调用'上已经单数和名称singularize'会导致问题。一个更好的选择是直接调用camelize,这是单数化后的分类电话 – DanneManne 2012-05-21 02:26:51

+0

编辑答案建议使用camelize来处理分类破坏以's'结尾但不是复数的模型名称的情况。 – 2012-10-22 15:20:36

+0

非常好。谢谢。前段时间我在自己的脚本上做了这些更改,我忘了在此更新它。我也提前撤消了对#sub的调用,取而代之的是使用#basename second arg,它可以删除文件扩展名。 – 2012-10-23 22:24:18

1

Rails的系统管理员使用此代码(见https://github.com/sferik/rails_admin/blob/master/lib/rails_admin/config.rb,方法viable_models):

([Rails.application] + Rails::Engine.subclasses.collect(&:instance)).flat_map do |app| 
      (app.paths['app/models'].to_a + app.config.autoload_paths).collect do |load_path| 
      Dir.glob(app.root.join(load_path)).collect do |load_dir| 
       Dir.glob(load_dir + '/**/*.rb').collect do |filename| 
       # app/models/module/class.rb => module/class.rb => module/class => Module::Class 
       lchomp(filename, "#{app.root.join(load_dir)}/").chomp('.rb').camelize 
       end 
      end 
      end 
     end.flatten.reject { |m| m.starts_with?('Concerns::') } 

的优点在于,它加载模型相关的发动机,不仅在当前的应用程序。

+1

关于这种方法的一些注意事项:1)'lchomp'不在Ruby标准库中,因此你必须将该行重写为'filename.gsub(“# {app.root.join(load_dir)} /“,'').gsub('。rb','')'或类似的,2)这会给你所有你可能已经在额外的加载路径中定义的类测试模块,在我的情况下),即使它们不是模型,所以你必须在内部块的某个地方添加一行'next,除非class_name.constantize.ancestors.include?(ActiveRecord :: Base)'。 – 2014-11-04 01:05:07

0

我试图在Rails 5下实现上述解决方案,但他们并没有完全工作。这里是指找到与“page_”开头的所有车型的溶液(或任何其他前缀,只需指定):

def self.page_models(prefix = "page") 
    models = [] 
    folder = File.join(Rails.root, "app", "models") 
    Dir[File.join(folder, "*")].each do |filename| 
    if filename =~ /models\/#{prefix}/ 
     klass = File.basename(filename, '.rb').camelize.constantize 
     models << klass 
    end 
    end 
    return models 
end 
相关问题