Несколько имеет и принадлежит многим отношениям - PullRequest
0 голосов
/ 15 апреля 2019

У меня есть модель, которая has_and_belongs_to_many связана с двумя другими моделями.Например, у меня есть модель Message, у которой есть получатели.Однако получателями могут быть модели двух разных типов.Например, InternalContact и ExternalContact.

Можно легко установить отношения, в которых я могу получить либо внешние контакты Сообщения (Message.first.external_contacts), либо его внутренние контакты (Message.first.internal_contacts).И затем я могу, в том же духе, легко добавить к этому массиву отношений (Message.first.external_contacts << ExternalContact.first)

То, что я хочу, - это способность просто вещи и делать это более эффективно, вызывая что-то вроде:

Message.first.recipients # an array of both external and internal contacts
Message.first.recipients << ExternalContact/InternalContact # (add either model)

Любое направление ценится, я определенно застрял!

Ответы [ 3 ]

1 голос
/ 15 апреля 2019

С явной моделью отношения «есть и принадлежит многим» (она же has_many through:) вы будете иметь больший контроль над отношением и сможете сделать его конец полиморфным:

class Message < ApplicationRecord
  has_many :message_recipients
  has_many :internal_recipients, through: :message_recipients, source: :recipient, source_type: "InternalContact"
end

class InternalContact < ApplicationRecord
  has_many :message_recipients, as: :recipient
  has_many :messages, through: :message_recipients, inverse_of: :internal_recipients
end

class MessageRecipient < ApplicationRecord
  belongs_to :message
  belongs_to :recipient, polymorphic: true
end


msg = Message.create!
rec = InternalContact.create!
msg.internal_recipients << rec
msg.message_recipients.each{|mr|
  mr.recipient # here can be any model
}
1 голос
/ 16 апреля 2019

Одним из способов сделать это, если вы хотите избежать полиморфной ассоциации, является использование 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
1 голос
/ 15 апреля 2019

Вы можете иметь отдельную таблицу типов получателей, а затем сопоставлять сообщения только с получателями

Recipient          Recipient_type   Message       Message_recipient_map
----------         ---------------  -------       -------------------
id                 id               id            message_id  
recipient_type_id                                 recipient_id 

Тогда вы можете иметь отношение has_many_through между сообщением и получателем и можете получить доступ ко всем получателям сообщения, вызвав message.recipients

Надеюсь, это поможет вам!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...