Краткий обзор полиморфных ассоциаций ActiveRecord.
При разработке наших приложений мы часто сталкиваемся с ситуациями, когда две или более разных моделей имеют ассоциации, которые кажутся идентичными. Например, у нас может быть модель продукта и услуги, в которой много фотографий, или модель проекта, подрядчика и задачи, в которой много комментариев. Один из способов решения этой проблемы - использовать одну дочернюю таблицу базы данных для каждой родительской модели:
class Product < ApplicationRecord has_many :photos, class_name: 'ProductPhotos' end class Service < ApplicationRecord has_many :photos, class_name: 'ServicePhotos' end class Project < ApplicationRecord has_many :comments, class_name: 'ProjectComments' end class Contractor < ApplicationRecord has_many :comments, class_name: 'ContractorComments' end class Task < ApplicationRecord has_many :comments, class_name: 'TaskComments' end
В качестве альтернативы мы можем использовать полиморфные ассоциации ActiveRecord для хранения этих похожих ассоциаций в одной таблице базы данных. Согласно Руководству по Ruby on Rails полиморфные ассоциации можно определить следующим образом:
С полиморфными ассоциациями модель может принадлежать нескольким другим моделям в одной ассоциации.
Мы смогли сгенерировать следующие модели:
rails g model Photo imageable:references{polymorphic} rails g model Comment commentable:references{polymorphic}
Что создает следующие миграции:
class
CreatePhotos < ActiveRecord::Migration[5.2] def change create_table :photos do |t| t.references :imageable, polymorphic: true t.timestamps end end end
class
CreateComments < ActiveRecord::Migration[5.2] def change create_table :comments do |t| t.references :commentable, polymorphic: true t.timestamps end end end
И соответствующие ассоциации ActiveRecord будут определены как таковые:
class
Photo <
ApplicationRecord belong_to :imageable end class Product < ApplicationRecord has_many :photos, as: :imageable end class Service < ApplicationRecord has_many :photos, as: :imageable end class Comment < ApplicationRecord belongs_to :commentable end class Project < ApplicationRecord has_many :comments, as: :commentable end class Contractor < ApplicationRecord has_many :comments, as: :commentable end class Task < ApplicationRecord has_many :comments, as: :commentable end
Под капотом полиморфной миграции были созданы два столбца в каждой полиморфной таблице: imageable_id и imageable_type в фотографиях и commentable_id и commentable_type в комментариях. Поскольку полиморфная таблица может принадлежать более чем одной другой модели, ActiveRecord использует столбец polymorphic_type для определения имени класса связи, из которого нужно найти правильный экземпляр с polymorphic_id.
В приведенных выше примерах imageable_type - это строка, которая может принимать значение Product или Service, а imageable_id - внешний ключ из одной из этих двух таблиц, тогда как commentable_type - это строка, которая может принимать значения Project, Contractor или Task, а commentable_id - внешний ключ из одной из этих трех таблиц.