是否有一种方法可以获得Rails应用程序中所有模型的集合?
基本上,我能做的是:-
Models.each do |model|
puts model.class.name
end
是否有一种方法可以获得Rails应用程序中所有模型的集合?
基本上,我能做的是:-
Models.each do |model|
puts model.class.name
end
当前回答
假设所有模型都在app/models中,并且你的服务器上有grep和awk(大多数情况下),
# extract lines that match specific string, and print 2nd word of each line
results = `grep -r "< ActiveRecord::Base" app/models/ | awk '{print $2}'`
model_names = results.split("\n")
它比Rails.application.eager_load快!或者用Dir遍历每个文件。
编辑:
这种方法的缺点是它忽略了间接继承自ActiveRecord的模型(例如FictionalBook < Book)。最可靠的方法是Rails.application.eager_load!;ActiveRecord::Base.descendants.map(&:name),尽管它有点慢。
其他回答
为了避免预加载所有Rails,你可以这样做:
Dir.glob("#{Rails.root}/app/models/**/*.rb").each {|f| require_dependency(f) }
require_dependency(f)和Rails.application.eager_load!用途。这应该可以避免已经要求的文件错误。
然后你可以使用各种解决方案来列出AR模型,如ActiveRecord::Base.descendants
是的,有很多方法可以找到所有的模型名称,但我在我的gem model_info中所做的是,它会给你所有的模型,甚至包括在gems中。
array=[], @model_array=[]
Rails.application.eager_load!
array=ActiveRecord::Base.descendants.collect{|x| x.to_s if x.table_exists?}.compact
array.each do |x|
if x.split('::').last.split('_').first != "HABTM"
@model_array.push(x)
end
@model_array.delete('ActiveRecord::SchemaMigration')
end
然后打印出来
@model_array
在Rails 6中,Zetiwerk成为默认的代码加载器。
对于快速加载,请尝试:
Zeitwerk::Loader.eager_load_all
Then
ApplicationRecord.descendants
确保在调用后代之前加载你的应用程序,这样所有的类都被加载了:
Rails.application.eager_load! unless Rails.application.config.eager_load
ApplicationRecord.descendants.each do |clazz|
# do something with clazz, e.g. User, Event, Attendance, etc.
end
编辑:看看评论和其他答案。有比这个更聪明的答案!或者尝试改进这个社区维基。
模型不会将自己注册到主对象,所以Rails没有模型列表。
但是您仍然可以在应用程序的models目录的内容中查找…
Dir.foreach("#{RAILS_ROOT}/app/models") do |model_path|
# ...
end
编辑:另一个(疯狂的)想法是使用Ruby反射来搜索每个扩展ActiveRecord::Base的类。我不知道你怎么列出所有的类…
编辑:只是为了好玩,我找到了一种列出所有职业的方法
Module.constants.select { |c| (eval c).is_a? Class }
编辑:终于成功地列出所有型号,而不查看目录
Module.constants.select do |constant_name|
constant = eval constant_name
if not constant.nil? and constant.is_a? Class and constant.superclass == ActiveRecord::Base
constant
end
end
如果你也想处理派生类,那么你需要测试整个超类链。我通过在Class类中添加一个方法来做到这一点:
class Class
def extend?(klass)
not superclass.nil? and ( superclass == klass or superclass.extend? klass )
end
end
def models
Module.constants.select do |constant_name|
constant = eval constant_name
if not constant.nil? and constant.is_a? Class and constant.extend? ActiveRecord::Base
constant
end
end
end