#ruby #ruby-on-rails-5 #single-table-inheritance
#ruby #ruby-on-rails-5 #single-table-inheritance
Вопрос:
Я пытаюсь создать простое приложение для подписи книг на Rails (книги, авторы, книжные магазины и т.д.), Используя наследование одной таблицы ( class Bookstore < Company
).
У меня есть следующее в config / application.rb:
config.autoload_paths = %W(#{config.root}.app/models/company)
И company.rb, и bookstore.rb находятся в каталоге app / models /company.
Bookstore.create(name: "Barnes and Noble")
находится в seeds.rb
При запуске rails db:seed
я получаю сообщение об ошибке uninitialized constant Bookstore
Также, если я нахожусь в консоли rails и делаю это Bookstore.new(...)
, я получаю ту же ошибку, но если я это делаю, Company.new(...)
я получаю undefined method 'new' for Company:Module
, что было удивительно, потому что я думал, что Company — это класс:
company.rb имеет class Company < ApplicationRecord
Как мне настроить наследование одной таблицы, чтобы я мог хранить классы в подкаталогах?
Я использую rails 5.2
Спасибо!
Комментарии:
1. Поместите классы в
app/models
вместоapp/models/company
2. Я не хочу, чтобы они были там, эта папка слишком переполнена. Я хочу знать, есть ли способ поместить файлы в подкаталоги
3. Rails автоматически загружает модели из вложенных папок, но ожидает, что у них будет пространство имен, поэтому, если
Bookstore
находится вapp/models/company
, вы бы написалиclass Company::Bookstore
4. Примечание о «слишком переполненном» — решение не должно быть «просто поместите его куда-нибудь еще», поскольку это только усложняет поиск части целого. Решение состоит в том, чтобы провести рефакторинг и полностью выделить значимую абстракцию, тем самым действительно сделав предыдущее целое «меньшим».
5. @benjessop означает ли это, что столбец типа в таблице companies будет содержать такие вещи, как Company::Bookstore? Есть ли способ обойти это?
Ответ №1:
Если вы хотите вложить свои модели в пространство имен, вы должны сделать это следующим образом:
class Company
end
# app/modules/companies/bookstore.rb
module Companies
class Bookstore < ::Company
end
end
# app/modules/companies/cafe.rb
module Companies
class Cafe < ::Company
end
end
Причина, по которой вы хотели бы использовать отдельную константу для пространства имен и не открывать константу повторно Company
, заключается в многочисленных ошибках и проблемах с классическим автозагрузчиком, используемым в Rails 5.2, и вложенностью модулей в классы.
Хотя вы могли бы добавлять пути к автозагрузчику, просто кажется глупым отказываться от дополнительной организации кода, которую дает вам вложение модуля. Это не похоже на загрязнение глобального пространства имен — отличная вещь.
Ответ №2:
Оказывается, есть опечатка:
config.autoload_paths = %W(#{config.root}.app/models/company)
должно быть
config.autoload_paths = %W(#{config.root}/app/models/company)
=> косая черта перед каталогом приложения вместо точки