Почему подклассы не инициализируются при наследовании одной таблицы Rails?

#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)

=> косая черта перед каталогом приложения вместо точки