2010-05-01 15 views
8

Ich möchte in der Lage sein, alle Modelle in meiner Rails-App zu durchlaufen und zu inspizieren. In Pseudo-Code würde es in etwa so aussehen:Wie kann ich alle Modelle in meiner Rails-App durchlaufen?

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

Meine Frage ist, wie überprüfen ich meine Rails-Anwendung eine Sammlung der Modelle (rails_env.models) zu bekommen?

Antwort

2

Iterieren Sie alle Dateien in `$ RAILS_ROOT \ app \ models '?

Zum Beispiel

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 

Does diese Hilfe?

9

Verwenden Sie ähnlich wie bei nathanvda die Option camelize statt groß, um Modelldateien mit Unterstrichen zu unterstützen, und verwenden Sie String # constantize statt Kernel.const_get.

Wenn Sie Nicht-ActiveRecord-Modelle in Ihrem Modellordner behalten (z. B. eine Suchklasse zum Konsolidieren der Suchlogik), sollten Sie überprüfen, ob die Klasse ein aktives Datensatzmodell ist.

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' ist in der Tat besser als' capitalize', aber es kann zu Problemen führen, da es 'singularize' auf Namen nennen, die bereits singulär sind und dass kann Probleme verursachen. Eine noch bessere Alternative wäre es, 'camelize' direkt zu nennen, was Klassifikationsaufrufe nach singularize sind. – DanneManne

+0

Bearbeitete Antwort, um die Verwendung von camelize zur Behandlung des Falles zu empfehlen, in dem Modellnamen verstümmelt werden, die in 's' enden, aber nicht Plural sind. –

+0

Ausgezeichnet. Vielen Dank. Ich habe diese Änderungen vor einiger Zeit an meinen eigenen Skripten vorgenommen, aber ich habe vergessen, sie hier zu aktualisieren. Ich bin auch weitergegangen und habe den Aufruf von #sub entfernt, stattdessen #basename second arg, der die Dateierweiterung entfernen kann. –

1

Rails Admin verwendet diesen Code (siehe https://github.com/sferik/rails_admin/blob/master/lib/rails_admin/config.rb, Methode 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::') } 

Der Vorteil ist, dass es Modelle in dazugehörigen Motoren, nicht nur in der aktuellen App lädt.

+1

Ein paar Anmerkungen zu diesem Ansatz: 1) 'lchomp' ist nicht in der Ruby-Standardbibliothek, also müssen Sie diese Zeile als' filename.gsub ("# {app.root.join (load_dir)}/", '') .gsub ('. rb', '')' oder ähnlich, und 2) dies gibt Ihnen alle Klassen, die Sie in zusätzlichen Ladepfaden definiert haben ((in meinem Fall Testmodule), auch wenn sie keine Modelle sind, also müssen Sie eine Zeile wie 'next außer class_name.constantise.ancestors.include? (ActiveRecord :: Base)' irgendwo im inneren Block hinzufügen. –

0

Ich habe versucht, die oben genannten Lösungen unter Rails 5 zu implementieren und sie haben nicht ganz funktioniert. Hier ist eine Lösung, die alle Modelle findet, die mit „Seite_“ beginnt (oder einem anderen Präfix müssen nur angeben, dass):

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 
Verwandte Themen