Rails: элегантный способ структурирования моделей в подпапки без создания подмодулей - PullRequest
61 голосов
/ 18 сентября 2009

У меня есть множество моделей в папке app / models. Я бы хотел немного почистить эту папку. Переместить модели, которые принадлежат друг другу в подпапках. Проблема заключается в том, что условный класс модели помещается в соответствующий модуль.

* 1003 Е.Г. *

приложение / модели / блог / post.rb
приложение / модели / блог / comment.rb
приложение / модели / user.rb

так что:

приложение / модели / блог / post.rb

class Post < ActiveRecord
end

а не

class Blog::Post < ActiveRecord
end

Ответы [ 10 ]

82 голосов
/ 25 января 2011

Вот что я использовал для Rails 3:

config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]

Эта конфигурация говорит Rails рекурсивно сканировать все подпапки приложения / модели и загружать все найденные модели. Пространство имен не требуется.

12 голосов
/ 19 сентября 2009

Нам нужно было это сделать, и есть очень простой способ.

переместите ваши модели в подпапки, а затем попросите rails загружать файлы из всех подпапок в вашем файле environment.rb:

config.load_paths += Dir["#{RAILS_ROOT}/app/models/*"].find_all { |f| File.stat(f).directory? }

Пространство имен не требуется, и модели могут называться в вашем приложении обычными

4 голосов
/ 19 марта 2014

Я также создал подпапки, а затем добавил следующее в файл application.rb:

config.autoload_paths += Dir["#{config.root}/app/models/**/"]

Но одного этого недостаточно, если имена подпапок имеют то же имя, что и модель (например, папка «пользователь», содержащая несколько файлов, один из которых «пользователь»). Это вызывало всевозможные ошибки в моем коде, пока я не обнаружил, что это можно решить, просто указав имена папок, которые отличаются от моделей (например, «пользовательских моделей»), которые они содержат. Я нашел предложение на http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-production/,, которое фактически указывает на этот вопрос.

3 голосов
/ 07 сентября 2011

Итак, я имел в Rails 2 что-то вроде этого:

config.autoload_paths += Dir["#{config.root}/app/models/**/"]

И следующие файлы:

  • app / models / user / base.rb: class User::Base
  • app / models / user / admin.rb: class User::Admin

Когда я обновлялся до Rails 3, я продолжал получать сообщение об этом: Expected .../app/models/user/foo.rb to define Foo. Это явно казалось сумасшедшим, поскольку Rails 2 автоматически предполагал, что то, что вы поместите в user / foo.rb, будет User::Foo, а не просто Foo.

Таким образом, в итоге я решил избавиться от подкаталогов модели в autoload_paths и сделать что-то вроде этого:

Я создал app / models / user.rb с:

module User
  autoload :User, 'user/base'
  autoload :User, 'user/admin'
end
1 голос
/ 05 апреля 2016

Это сработало для меня в Rails 5.

Добавление следующего к application.rb

config.autoload_paths += Dir[ Rails.root.join('app/models/**/') ]

Будьте осторожны, так как в вашей папке не может быть того же имени, что и у любой из ваших моделей.

1 голос
/ 23 апреля 2012

В моем приложении Rails 3.2.3, после того, как я переместил некоторые модели в подкаталоги, я столкнулся с ошибками типа

Expected /.../.../app/models/project/project_category.rb to define Project::ProjectCategory

для вызовов ассоциации (пример: Project.first.project_category).

В итоге я нашел обходной путь: имя_класса для каждой ассоциации для моделирования в подкаталоге ...

class Project < ActiveRecord::Base

  belongs_to :project_category, :class_name => "::ProjectCategory"

end

Часть "::" здесь указывает Rails, что модель ProjectCategory не имеет пространства имен, несмотря на то, что это определено в подкаталоге models / project.

1 голос
/ 27 октября 2010

эта версия решения Tilendor работает с Rails 3

config.load_paths и RAILS_ROOT устарели в Rails 3, также вы должны поместить его в блок config config / application.rb, а не environment.rb

config.autoload_paths += Dir["#{Rails.root.to_s}/app/models/*"].find_all { |f| File.stat(f).directory? }
1 голос
/ 19 сентября 2009

Может быть, вы могли бы взглянуть на RailsEngines. Это не совсем то, что вам нужно, но может дать вам несколько идей.

Кроме этого, если ваш скрипт работает нормально (вы также можете просто прочитать все файлы в каждой подпапке на модели и потребовать их), я не вижу никаких проблем с этим.

0 голосов
/ 06 июня 2013

Все приведенные выше ответы не сработали для меня. Каким-то образом папка «models» была загружена с подпапками, в результате чего «Ожидается, что содержит ::.

Большинство моих подкаталогов были классами STI, поэтому я переместил их в app / models_sti // *. Тогда все, что мне нужно было сделать, это вставить 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
0 голосов
/ 18 сентября 2009

Пока я не найду лучшего решения, я создал файл init.rb в папке app / models:

приложение / модели / init.rb

%w[blog].each do |folder|
  path = [File.dirname(__FILE__), folder, "*.rb"].join('/')
  Dir[path].each {|file| require file }  
end

Серверы цели до сих пор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...