ruby on rails - rails - Rieles: forma elegante de estructurar modelos en subcarpetas sin crear submódulos
rails sql query (10)
Así que solía tener en Rails 2 algo como esto:
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Y los siguientes archivos:
- app / models / user / base.rb:
class User::Base
- app / models / user / admin.rb:
class User::Admin
Cuando actualicé a Rails 3, seguí recibiendo un error en esta línea: Expected .../app/models/user/foo.rb to define Foo
. Esto claramente parecía una locura ya que Rails 2 automáticamente asumió que lo que pusiste en user / foo.rb sería User::Foo
no solo Foo
.
Así que la forma en que terminé resolviendo esto fue deshacerme de los subdirectorios de modelos en autoload_paths
y hacer algo como esto:
Creé app / models / user.rb con:
module User
autoload :User, ''user/base''
autoload :User, ''user/admin''
end
Tengo numerosos modelos en mi carpeta de aplicaciones / modelos. Me gustaría limpiar esta carpeta un poco. Mueva los modelos que pertenecen el uno al otro en subcarpetas. El problema es que, por convención, la clase de modelo tiene un espacio de nombres en un módulo correspondiente.
P.ej
app / models / blog / post.rb
app / models / blog / comment.rb
app / models / user.rb
así que eso:
app / models / blog / post.rb
class Post < ActiveRecord
end
y no
class Blog::Post < ActiveRecord
end
En mi aplicación Rails 3.2.3, después de mover algunos modelos a subdirectorios, he tropezado con errores como
Expected /.../.../app/models/project/project_category.rb to define Project::ProjectCategory
para llamadas de asociación (ejemplo: Project.first.project_category).
Al final, la solución alternativa que encontré fue establecer: class_name para cada asociación para modelar en subdirectorio ...
class Project < ActiveRecord::Base
belongs_to :project_category, :class_name => "::ProjectCategory"
end
"::" apunta aquí a Rails que el modelo ProjectCategory no tiene espacio de nombre, a pesar del hecho de que está definido en un subdirectorio ''modelos / proyecto''.
Esto es lo que utilicé para Rails 3:
config.autoload_paths += Dir[Rails.root.join(''app'', ''models'', ''{**}'')]
Esta configuración le dice a Rails que escanee todas las subcarpetas de aplicaciones / modelos recursivamente y cargue todos los modelos encontrados. No se requiere espacio de nombres.
Esto funcionó para mí en Rails 5.
Agregando lo siguiente a application.rb
config.autoload_paths += Dir[ Rails.root.join(''app/models/**/'') ]
Sin embargo, ten en cuenta que no puedes tener el mismo nombre en tu carpeta que cualquiera de tus modelos.
Hasta que encuentre una mejor solución, he creado un init.rb en la carpeta de la aplicación / modelos:
app / models / init.rb
%w[blog].each do |folder|
path = [File.dirname(__FILE__), folder, "*.rb"].join(''/'')
Dir[path].each {|file| require file }
end
Servidores del propósito hasta ahora.
Necesitábamos hacer esto, y hay una manera muy simple.
mueva sus modelos a las subcarpetas y luego pida a los rieles que carguen los archivos de todas las subcarpetas en su archivo environment.rb:
config.load_paths += Dir["#{RAILS_ROOT}/app/models/*"].find_all { |f| File.stat(f).directory? }
No se requiere espacio de nombres, y los modelos se pueden referir como normales en tu aplicación
Tal vez podrías mirar RailsEngines. No es exactamente lo que necesita, pero podría darle algunas ideas.
Aparte de eso, si su script parece funcionar bien (también podría simplemente leer todos los archivos en cada subcarpeta en el modelo y requerirlos), no veo ningún problema en contra de ello.
También creé subcarpetas, y luego agregué lo siguiente al archivo application.rb:
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Pero hacer esto solo no es suficiente cuando las subcarpetas se nombran usando el mismo nombre que un modelo (por ejemplo, una carpeta ''usuario'' que contiene varios archivos, uno de los cuales es ''usuario''). Esto estaba causando todo tipo de errores en mi código hasta que descubrí que podía ser resuelto simplemente dando a las carpetas nombres diferentes de los modelos (por ejemplo, ''modelos de usuario'') que contienen. Encontré la sugerencia en http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-production/ , que en realidad apunta a esta pregunta.
Todas las respuestas anteriores no funcionaron para mí. De alguna manera, la carpeta ''modelos'' se cargó con subcarpetas, lo que resultó en ''Se espera que contenga ::.
La mayoría de mis subdirectorios eran clases de STI, así que los moví a la aplicación / models_sti // *. Entonces todo lo que tenía que hacer era ponerlo en la application.rb
#config.autoload_paths += Dir["#{Rails.root.to_s}/app/models/**/"]
# Loaded dynamically (cache_classes == false ?)
config.autoload_paths << Rails.root.join(''app'', ''models'').to_s
config.autoload_paths += Dir["#{Rails.root.to_s}/app/models_sti/*"].find_all { |f| File.stat(f).directory? }
# Eager_load_paths - used only when cache_classes == true [rails spec says so]
config.eager_load_paths.delete_if do |path|
# If I didn''t delete it from eager_load_paths I got errors even in develop
path == Rails.root.join(''app'', ''models_sti'').to_s
end
config.eager_load_paths += config.autoload_paths
esta versión de la solución de Tilendor funciona con Rails 3
config.load_paths y RAILS_ROOT están en desuso en Rails 3, también debe ponerlo en el bloque de configuración de config / application.rb, no environment.rb
config.autoload_paths += Dir["#{Rails.root.to_s}/app/models/*"].find_all { |f| File.stat(f).directory? }