我想能夠迭代並檢查我的Rails應用程序中的所有模型。在僞代碼,它看起來是這樣的:如何遍歷我的rails應用程序中的所有模型?
rails_env.models.each do |model|
associations = model.reflect_on_all_associations(:has_many)
... do some stuff
end
我的問題是我如何檢查我的Rails應用程序來獲取模型(rails_env.models)的集合?
我想能夠迭代並檢查我的Rails應用程序中的所有模型。在僞代碼,它看起來是這樣的:如何遍歷我的rails應用程序中的所有模型?
rails_env.models.each do |model|
associations = model.reflect_on_all_associations(:has_many)
... do some stuff
end
我的問題是我如何檢查我的Rails應用程序來獲取模型(rails_env.models)的集合?
迭代'$ 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
這是否幫助?
與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
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)'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
我試圖在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
如果你只在一個現代化的Rails應用程序望着ApplicationRecord模型,你可以只使用
ApplicationRecord.descendants
在這裏,你可以看看它:http://apidock.com/rails/Class/descendants
'classify'確實比'capitalize'更好,但它可能會導致問題,因爲它會調用'上已經單數和名稱singularize'會導致問題。一個更好的選擇是直接調用camelize,這是單數化後的分類電話 – DanneManne 2012-05-21 02:26:51
編輯答案建議使用camelize來處理分類破壞以's'結尾但不是複數的模型名稱的情況。 – 2012-10-22 15:20:36
非常好。謝謝。前段時間我在自己的腳本上做了這些更改,我忘了在此更新它。我也提前撤消了對#sub的調用,取而代之的是使用#basename second arg,它可以刪除文件擴展名。 – 2012-10-23 22:24:18