2010-05-01 10 views
8

Me gustaría poder repetir e inspeccionar todos los modelos en mi aplicación de rieles. En pseudo-código que se vería algo como:¿Cómo puedo iterar a través de todos los Modelos en mi aplicación de rieles?

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

Mi pregunta es ¿cómo puedo inspeccionar mis rieles de aplicaciones para obtener una colección de los modelos (rails_env.models)?

Respuesta

2

Iterar todos los archivos en `$ RAILS_ROOT \ app \ models '?

Por ejemplo

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 

¿Esto ayuda?

9

Similar a la respuesta de nathanvda, utilice camelize en lugar de mayúsculas para admitir archivos de modelo con guiones bajos, y use String # constantize en lugar de Kernel.const_get.

Además, si mantiene los modelos de registro no activo en la carpeta de modelos (por ejemplo, una clase de búsqueda para consolidar la lógica de búsqueda), querrá verificar que la clase sea un modelo de registro activo.

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' es de hecho mejor que' capitalize', sin embargo, puede causar problemas, ya que llamará 'singularize' de nombres que ya son singulares y que puede causar problemas. Una alternativa aún mejor sería llamar 'camelize' directamente, que es lo que clasifica llamadas después de singularizar – DanneManne

+0

Respuesta editada para sugerir el uso de camelize para manejar el caso en que classify mutila nombres de modelo que terminan en 's' pero no son en plural. –

+0

Excelente. Gracias. Hice estos cambios en mis propios scripts hace un tiempo, me olvidé de actualizarlo aquí. También me adelanté y eliminé la llamada a #sub, en su lugar usé #basename second arg, que puede eliminar la extensión del archivo. –

1

rieles de administración utiliza este código (ver https://github.com/sferik/rails_admin/blob/master/lib/rails_admin/config.rb, viable_models método):

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

La ventaja es que se carga en los motores de los modelos asociados, no sólo en su aplicación actual.

+1

Algunas notas sobre este enfoque: 1) 'lchomp' no está en la lib lib del estándar, por lo que tendrá que reescribir esa línea como' filename.gsub ("# {app.root.join (load_dir)}/", '') .gsub ('. rb', '')' o similar, y 2) esto le dará todas las clases que haya definido en rutas de carga adicionales (módulos de prueba, en mi caso), incluso si no son modelos, por lo que tendrá que agregar una línea como 'next a menos que class_name.constantize.ancestors.include? (ActiveRecord :: Base)' en algún lugar del bloque interno. –

0

Intenté implementar las soluciones anteriores en Rails 5 y no funcionaron del todo. He aquí una solución que encuentra todos los modelos que se inicia con "página_" (o cualquier otro prefijo, sólo se especifica 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 
Cuestiones relacionadas