Для наследования моделей с общей таблицей используют STI: подклассы наследуют базовую модель, а столбец type по умолчанию хранит имя класса. Полиморфная ассоциация не является наследованием: belongs_to с polymorphic: true хранит пару идентификатор/тип связанного объекта. STI связывает модели общей схемой; полиморфная связь усложняет обеспечение ссылочной целостности обычными внешними ключами.
Как реализовать наследование моделей или полиморфные ассоциации в Ruby on Rails?
STI хранит иерархию моделей в общей таблице, а полиморфная ассоциация связывает запись с объектами разных моделей. Это разные механизмы.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Это две разные задачи. STI, или Single Table Inheritance, реализует наследование моделей с хранением в одной таблице. Полиморфная ассоциация описывает связь с объектами разных моделей, а не наследование между ними.
Для STI создадим общую таблицу. Фрагмент тела change в миграции:
create_table :animals do |t|
t.string :type
t.string :name
end
Модели размещаются в соответствующих файлах, например animal.rb, dog.rb и cat.rb:
class Animal < ApplicationRecord; end
class Dog < Animal; end
class Cat < Animal; end
dog = Dog.create!(name: 'Рекс')
Animal.find(dog.id).class # => Dog
По умолчанию Rails записывает имя подкласса в строковый столбец type и по нему восстанавливает объект. Отдельные таблицы dogs и cats здесь не нужны. Столбец можно переименовать настройкой inheritance_column; нельзя бездумно использовать type для постороннего бизнес-поля. Настройка inheritance_column.
Для комментариев к статьям и фотографиям наследование не требуется. Предположим, таблицы articles и photos уже существуют. Фрагмент другой миграции:
create_table :comments do |t|
t.text :body
t.references :commentable, polymorphic: true, null: false, index: true
end
Соответствующие модели:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Article < ApplicationRecord
has_many :comments, as: :commentable
end
class Photo < ApplicationRecord
has_many :comments, as: :commentable
end
Поля commentable_type и commentable_id определяют тип и идентификатор владельца. comment.commentable вернёт соответствующую статью или фотографию. При переименовании модели нужно согласовать сохранённые значения типа с кодом.
STI удобно при близких атрибутах и поведении, но общая схема может обрастать столбцами, нужными лишь одному подклассу. Полиморфная связь гибче по составу владельцев, однако обычный внешний ключ не может по значению типа выбирать одну из нескольких целевых таблиц. Правила удаления и ссылочную целостность приходится проектировать отдельно; null: false проверяет лишь отсутствие NULL. Руководство по ассоциациям и STI.