Одним из способов сделать это, если вы хотите избежать полиморфной ассоциации, является использование Single Table Inheritance .
Одной из основных причин, по которой вы хотели бы это сделать, является возможность использовать внешний ключ для обеспечения ссылочной целостности, что невозможно при полиморфизме.
Поскольку типы совместно используют таблицу, вы также можете рассматривать их как однородную коллекцию, когда дело доходит до упорядочения.
Но наследование одной таблицы действительно подходит, только если разные типы очень похожи по природе и взаимозаменяемы.
Настройка STI
Сначала создайте таблицу contacts
, в которой вы будете хранить все различные типы.
class CreateContacts < ActiveRecord::Migration[5.2]
def change
create_table :contacts do |t|
t.string :type
# and whatever columns you need
t.string :email
# ...
t.timestamps
end
end
end
Обратите внимание на столбец type
. ActiveRecord будет использовать это для хранения имени класса подклассов. Затем настройте InternalContact и ExternalContact для наследования от базового Contact
класса:
class InternalContact < Contact
# ...
end
class ExternalContact < Contact
# ...
end
Это позволяет вам реализовать любую логику, которую вы хотите (например, проверки и обратные вызовы) для каждого подтипа.
Ассоциации
Начните с таблицы соединений:
class CreateMessageRecipients < ActiveRecord::Migration[5.2]
def change
create_table :message_recipients do |t|
t.belongs_to :message
t.belongs_to :recipient, foreign_key: { to_table: :contacts }
t.timestamps
end
end
end
Позволяет установить ассоциации с has_many through:
и моделью соединения вместо has_and_belongs_to_many
, которая очень ограничена:
class Contact < ApplicationRecord
has_many :message_recipients, foreign_key: :recipient_id
has_many :messages, through: :message_recipients
end
class MessageRecipient < ApplicationRecord
belongs_to :message
belongs_to :recipient, class_name: 'Contact'
end
class Message < ApplicationRecord
has_many :message_recipients
has_many :recipients, through: :message_recipients
end