¿Hay alguna manera de obtener una colección de todos los modelos en tu aplicación Rails?
¿Existe alguna manera de obtener una colección de todos los modelos en su aplicación Rails?
Básicamente, ¿puedo hacer cosas como: -
Models.each do |model|
puts model.class.name
end
La respuesta completa para Rails 3, 4 y 5 es:
Si cache_classes
está desactivado (de forma predeterminada, está desactivado en desarrollo, pero activado en producción):
Rails.application.eager_load!
Entonces:
ActiveRecord::Base.descendants
Esto garantiza que todos los modelos de su aplicación, independientemente de dónde se encuentren, estén cargados y que también se carguen todas las gemas que esté utilizando y que proporcionen modelos.
Esto también debería funcionar en clases que heredan de ActiveRecord::Base
, como ApplicationRecord
en Rails 5, y devolver solo ese subárbol de descendientes:
ApplicationRecord.descendants
Si desea saber más sobre cómo se hace esto, consulte ActiveSupport::DescendantsTracker .
En caso de que alguien se tope con esto, tengo otra solución, sin depender de la lectura de directorios ni de extender la clase Class...
ActiveRecord::Base.send :subclasses
Esto devolverá una serie de clases. Entonces puedes hacer
ActiveRecord::Base.send(:subclasses).map(&:name)
EDITAR: mire los comentarios y otras respuestas. ¡Hay respuestas más inteligentes que ésta! O intente mejorar este como wiki comunitario.
Los modelos no se registran en un objeto maestro, entonces no, Rails no tiene la lista de modelos.
Pero aún puedes buscar en el contenido del directorio de modelos de tu aplicación...
Dir.foreach("#{RAILS_ROOT}/app/models") do |model_path|
# ...
end
EDITAR: Otra idea (loca) sería utilizar la reflexión de Ruby para buscar todas las clases que extiendan ActiveRecord::Base. Aunque no sé cómo puedes enumerar todas las clases...
EDITAR: Solo por diversión, encontré una manera de enumerar todas las clases.
Module.constants.select { |c| (eval c).is_a? Class }
EDITAR: Finalmente logré enumerar todos los modelos sin mirar directorios
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
Si también desea manejar clases derivadas, deberá probar toda la cadena de superclases. Lo hice agregando un método a la clase 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
ActiveRecord::Base.connection.tables.map do |model|
model.capitalize.singularize.camelize
end
regresará
["Article", "MenuItem", "Post", "ZebraStripePerson"]
Información adicional Si desea llamar a un método con el nombre del objeto sin modelo: método desconocido de cadena o errores de variable, use esto
model.classify.constantize.attribute_names