ここでは、ポリモーフィックな関係を使用する必要はないようです。あなたはこれを行うことができるはずです:
class User < ActiveRecord::Base
has_many :participations, class_name: 'Participant'
has_many :conversations, through: :participations
has_many :conversation_items, through: :conversations
end
class Participant < ActiveRecord::Base
belongs_to :user
belongs_to :conversation
end
class Conversation < ActiveRecord::Base
has_many :participants
has_many :conversation_items
end
class ConversationItem < ActiveRecord::Base
belongs_to :conversation
belongs_to :sender, class_name: 'User', foreign_key: 'sender_id'
end
私にとって、これは会話に多くの参加者がいるドメインモデルとしてより理にかなっています。送信者を会話アイテムに添付することができ、送信者ではない会話のすべての参加者が暗黙的に受信者になります。会話は双方向または多方向の対話であるため、会話に送信者と受信者が含まれることは意味がありません。
ここでポリモーフィック関係が機能しない理由は、ポリモーフィック関係は、テーブルがさまざまなタイプのアイテムを参照できる状況のためのものであるためです。たとえば、ConversationItemに多くの添付ファイルがあり、添付ファイルを投稿に適用できるとします。あなたは次のようなものを持っているでしょう:
class ConversationItem < ActiveRecord::Base
#...
has_many :attachments, as: :attachable
#...
end
class Post < ActiveRecord::Base
has_many :attachments, as: :attachable
end
class Attachment < ActiveRecord::Base
belongs_to :attachable, polymorphic: true
end
添付ファイルにフィールドattachable_id
とが含まれる場所attachable_type
。会話アイテムから添付ファイルをクエリすると、のようなクエリが作成されますSELECT * FROM attachments where attachable_id = <id of the conversation item> and attachable_type = 'ConversationItem'
。したがって、ポリモーフィックアソシエーションにより、モデルを他の多くの異なるタイプのモデルにアタッチすることができます。
この場合、conversation_itemsテーブルに、、、、があるため、会話アイテムを送受信するさまざまなタイプのモデルがない限り、ポリモーフィックな関係を持つことがどのようsender_type
に意味をなさないかがわかります。 sender_id
recipient_type
recipient_id
モデルに関するもう1つの問題は、異なるパラメーターを使用して同じ関係を2回定義しようとしていることです。を呼び出すとhas_many :foo
、Railsは、、などのさまざまなメソッドを生成しfoos
ますfoos=
。もう一度呼び出すと、これらのメソッドを新しいパラメーターで再定義しているだけです。
ファローアップ
必ずしも参加者モデルを持っている必要はありません。これを使用すると、複数のユーザーを参加させることができ、同じモデルに対して複数の関係を作成することを回避できます。リレーションシップでも同じことを実現できhas_and_belongs_to_many
ますが、必要が生じた場合に、結合テーブルに追加の属性をアタッチする機能が失われます。
たとえば、参加者がかつて参加者であったことを削除せずに会話を終了できるようにしたい場合、参加モデルを使用すると、誰かが終了するときactive
に設定するブールフィールド呼び出しを追加できます。false
HABTMでは、それはできませんでした。参加者を退会させるには、ペアを結合テーブルから完全に削除する必要があります。スキーマがどのように進化するかわからないので、私は通常、ここの参加モデルのような結合モデルを好みます。
そうは言っても、これがHABTMの例です。
class User < ActiveRecord::Base
has_and_belongs_to_many :conversations
end
class Conversation < ActiveRecord::Base
has_and_belongs_to_many :users
end
ここには結合モデルはありませんが、これを機能させるには結合テーブルを作成する必要があります。そのための移行の例は次のとおりです。
create_table :conversations_users, :id => false do |t|
t.integer :conversation_id
t.integer :user_id
end
add_index :conversations_users, [:conversation_id, :user_id], unique: true
結合テーブルの構成要素の名前がアルファベット順に配置されている場合、つまりconversations_users
、ではありませんusers_conversations
。
さらなるフォローアップ
参加者テーブルを使用する場合、外部キーはオンparticipants
とになりconversation_items
ます。
participants
user_id
conversation_id
conversation_items
conversation_id
sender_id