2010-05-01 14 views
8

Je voudrais pouvoir parcourir et inspecter tous les modèles dans mon application rails. En pseudo-code, il ressemblerait à quelque chose comme:Comment puis-je parcourir l'ensemble de l'application Modèles dans mes rails?

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

Ma question est de savoir comment puis-je inspecter mon rails app pour obtenir une collection des modèles (rails_env.models)?

Répondre

2

Effectue une itération sur tous les fichiers de `$ RAILS_ROOT \ app \ models '?

Par exemple

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 

cette aide?

9

Similaire à la réponse de nathanvda, utilisez camelize plutôt que de capitaliser pour prendre en charge les fichiers modèles avec des traits de soulignement, et utilisez la chaîne # constantize plutôt que Kernel.const_get. En outre, si vous conservez des modèles non-activationecord dans votre dossier models (par exemple, une classe de recherche pour la consolidation de la logique de recherche), vous devez vérifier que la classe est un modèle d'enregistrement actif.

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' est en effet mieux que' capitalize', mais il peut causer des problèmes, car il appellera 'singularize' sur les noms qui sont déjà singulier et que peut causer des problèmes. Une alternative encore meilleure serait d'appeler 'camelize' directement, ce qui classifie les appels après singulariser – DanneManne

+0

Edited answer pour suggérer l'utilisation de camelize pour gérer le cas où classify mutile les noms de modèles qui se terminent par 's' mais ne sont pas pluriels. –

+0

Excellent. Merci. J'ai fait ces changements sur mes propres scripts il y a un moment, j'ai juste oublié de le mettre à jour ici. Je suis également allé en avant et ai enlevé l'appel à #sub, au lieu d'utiliser #basename second arg qui peut enlever l'extension de fichier. –

1

Rails Administrateur utilise ce code (voir https://github.com/sferik/rails_admin/blob/master/lib/rails_admin/config.rb, viable_models méthode):

([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::') } 

L'avantage étant qu'il charge les modèles dans les moteurs associés, pas seulement dans votre application actuelle.

+1

Quelques remarques à propos de cette approche: 1) 'lchomp' n'est pas dans la librairie standard Ruby, donc vous devrez réécrire cette ligne comme' filename.gsub ("# {app.root.join (load_dir)}/",") .gsub ('.rb', '') 'ou similaire, et 2) cela vous donnera toutes les classes que vous avez définies dans des chemins de chargement supplémentaires (tester des modules, dans mon cas), même s'ils ne sont pas des modèles, vous devrez donc ajouter une ligne comme 'next sauf si class_name.constantize.ancestors.include? (ActiveRecord :: Base)' quelque part dans le bloc interne. –

0

J'ai essayé d'implémenter les solutions ci-dessus sous Rails 5 et ils n'ont pas vraiment fonctionné. Voici une solution qui trouve tous les modèles qui commence par « page_ » (ou tout autre préfixe, il suffit de préciser que):

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