コメント機能の実装
概要
- ポートフォリオとして作成する学習マッチングアプリの中で、コミュニケーションツールを実装したい。
- twitterをイメージしたツールにしたい。
- ユーザ間のコミュニケーションを想定する。
アソシエーション
テーブル定義
Commentsテーブル
ReplyRelationshipsテーブル
モデル
commentには、メインとなるコメントと返信コメントがある。そのため、同じCommentモデルで2つの異なるアソシエーションが必要となる。それを実現させるために、以下のようなアソシエーションを設定した。
ReplyRelationshipモデル
同じCommentモデルと2つの異なるアソシエーションを設定するために、class_nameを使用する。
このように宣言すると、@reply_relationship.main_commentや@reply_relationship.replyといった使い方ができる。
また、意訳すると、「Commentモデルに対して、main_commentって名前でbelongs_toの関連付けしときますね」ということになる。
今回は、返信コメントがある時に、このモデルが活躍するので、replyが削除された時点でreply_relationshipは不要であるため、replyのみ「dependent: :destroy」としている
Commentモデル
上記に付随する形で、CommentモデルでもReplyRelationshipモデルと2種類の異なるアソシエーションが必要となる。
まず、上記の2つは、class_nameを使用して、ReplyRelationshipモデルと異なる2つのアソシエーションを設定している。
このように宣言することで、@comment.replying_relationshipや、@comment.replied_relationshipsのように使うことができる。
また、意訳すると、「ReplyRelationshipモデルに対して、reply_idを見て、replying_relationshipって名前でアソシエーション設定しますね」となる。
次に、上記の2つは、throughとsourceを使用している。それぞれ、
- through 経由するモデル名を指定する
- source 関連先モデル名を指定する
throughによる関連付けは、2つのモデルの間に第3のモデルが存在する場合に用いるのが一般的である。しかし、今回はComment → ReplyRelationship → Comment であるため、sourceでそれぞれ名前付けをして区別している。また、上記で定義したReplyRelationshipモデルの名前をthroughに使用する。
このように宣言することで、@comment.replyingや@comment.repliedのように使うことができる。
また、意訳すると、「replying_relationshipモデルを経由して、main_commentモデルに対して、replyingって名前でアソシエーションしときますね」となる。
まとめ
このようにすることで、CommentモデルとReplyRelationshipモデルで2種類の異なるアソシエーションを設定することができた。こうすることで、db上は同じCommentsテーブルに存在するにも関わらず、メインのコメントであるのか、返信コメントであるのかの区別ができるようになった。
Railsはあらかじじめかなり便利なメソッドが複数存在しているが、多言語で同じことをしようとした時に、どうやってアソシエーションを実現させるのか気になった。
コメントを返信する際に、返信コメント用のモーダルも実装したので、それも追記するか、新しい記事にしたいと思う。
参考
【Railsチュートリアル】フォロー機能のアソシエーションを解説してみる
【rails】Twitterのツイート機能のモデル構造を考えてみた
公式 Active Record の関連付け