1

これは簡単に解決できるはずですが、私はRailsを初めて使用します。現在、アソシエーションに関するレールガイドを詳しく調べていますが、常に障害にぶつかっています。

他のユーザーにメッセージを送信できるユーザーモデルがあります。そのために、すべてのスレッドの会話モデルと、個々のメッセージごとのconversation_itemモデルがあります。

これらは現在の関連付けです。

User.rb

has_many :received_messages, as: :recipient, class_name: 'Conversation', foreign_key: :recipient_id
has_many :sent_messages, as: :sender, class_name: 'Conversation', foreign_key: :sender_id
has_many :received_messages, as: :recipient, class_name: 'Conversation_item', foreign_key: :recipient_id
has_many :sent_messages, as: :sender, class_name: 'Conversation_item', foreign_key: :sender_id

Conversation.rb

has_many :conversation_items, dependent: :destroy
belongs_to :sender, polymorphic: true
belongs_to :recipient, polymorphic: true

Conversation_item.rb

belongs_to :conversation
belongs_to :sender, polymorphic: true
belongs_to :recipient, polymorphic: true

私は次のような会話アイテムを介してユーザーにアクセスしようとしています。

<%= conversation_item.sender.inspect %>

これは戻りますnil-属性送信者は機能しているように見えますが、どういうわけか何も含まれていません。ただし、会話アイテムには実際にsender_idがあります。

上記の関連付けで何が欠けていますか?または他のどこか?

4

2 に答える 2

2

ここでは、ポリモーフィックな関係を使用する必要はないようです。あなたはこれを行うことができるはずです:

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_idrecipient_typerecipient_id

モデルに関するもう1つの問題は、異なるパラメーターを使用して同じ関係を2回定義しようとしていることです。を呼び出すとhas_many :foo、Railsは、、などのさまざまなメソッドを生成しfoosますfoos=。もう一度呼び出すと、これらのメソッドを新しいパラメーターで再定義しているだけです。

ファローアップ

必ずしも参加者モデルを持っている必要はありません。これを使用すると、複数のユーザーを参加させることができ、同じモデルに対して複数の関係を作成することを回避できます。リレーションシップでも同じことを実現できhas_and_belongs_to_manyますが、必要が生じた場合に、結合テーブルに追加の属性をアタッチする機能が失われます。

たとえば、参加者がかつて参加者であったことを削除せずに会話を終了できるようにしたい場合、参加モデルを使用すると、誰かが終了するときactiveに設定するブールフィールド呼び出しを追加できます。falseHABTMでは、それはできませんでした。参加者を退会させるには、ペアを結合テーブルから完全に削除する必要があります。スキーマがどのように進化するかわからないので、私は通常、ここの参加モデルのような結合モデルを好みます。

そうは言っても、これが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
于 2012-12-08T20:24:03.510 に答える
-1

モデルのロジックは問題ないようです。私の提案は、コントローラーとビューの構造です。Railsで関連付けを作成する場合、(routes.rb内の)リソースをネストするための一般的なアプローチは次のとおりです。

リソース:会話はリソースを実行します:conversation_items終了

次に、Conversation_itemsコントローラーは、newおよびcreateアクションで次のようなものを持っている必要があります。

def new
  @conversation = Conversation.find(params[:conversation_id]
  @conversation_item = Conversation_item.new
end

def create
  @conversation = Conversation.find(params[:conversation_id]
  @conversation_item = @conversation.conversation_items.build(params[:conversation_items]
end

そして最後に、_form.html.erb(作成アクションと更新アクションの両方を提供します)で:

  <%= form_for [@conversation, @conversation_item] do |f| %>

     # your code here

  <%= end %>

あなたがここで見ることができるように、私はそこにいました...それはほろ苦いです:)

于 2012-12-08T18:47:48.210 に答える