#実装内容
今回はコメントに対する返信機能の作成です
- 返信テーブルはコメントテーブルと同じです。
- コメントの返信フォームからコメントを送信すると、そのコメントに対しての返信になる
- コメントTableにreply_commentを追加し、そこに親コメントのidを入れる
#実装コード
コメントテーブルに返信用カラムを作ります。
ここには、親コメントidを格納される予定です。
rails g migration AddReply_user_idToComment reply_comment:int
##モデル
model/product.rb
has_many :comments
has_many :replies, class_name: Comment, foreign_key: :reply_comment, dependent: :destroy
model/comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :product
end
外部キーにreply_commentを登録。
いまいちprimary_keyとforeign_keyあたりの使い方は理解できてません。
##コントローラ
ツイート詳細ページにてコメントできるようにします。
controller/comments_controller.rb
class CommentsController < ApplicationController
#コメント削除アクション
def destroy
@comment = Comment.find(params[:id]).destroy
redirect_to "/products/#{@comment.product.id}"
end
#コメント追加アクション
def create
@comment = Comment.create(comment_params)
# @product = Comment.find_by(product_id: params[:product_id])
redirect_to "/products/#{@comment.product.id}"
end
private
#ストロングパラメータ
#返信機能のためにreply_commentを追加
def comment_params
comment_params = params.require(:comment).permit(:content, :image,:reply_comment).merge(user_id: current_user.id, product_id: params[:product_id])
end
end
controller/products_controller.rb
def show
@product = Product.find(params[:id])
#指定のツイートのコメントを列挙
@comments = Comment.includes(:user).where(product_id: @product.id)
#いいね機能
@like = Like.find_by(user_id: current_user.id)
@likes = Like.new(user_id: current_user.id, product_id: params[:product_id])
#コメント追加
@new_comments = Comment.new
end
アソシエーションを用いるとcomments.userを使えるが、eachメソッドの内部で用いるとN+1問題が発生するので、includesメソッドで先にuserテーブルの情報も取得しておく。
気になったこと
先にuserテーブルの情報を取得すると書いてあったが、これってどこに格納されるんだ・・・
##View
products/show.html.erb
#コメントの一覧
<% @comments.each do |comment| %>
<li class="collection-item">
<div>
#ユーザー情報カードの部分テンプレートへ
<%= render 'products/user' , user: comment.user %><br>
#親コメントが存在する場合、出力
<% unless comment.reply_comment == nil %>
コメント先-----------<br>
#親コメントのユーザーを出力
<%= render 'products/user' , user: @comments.find(comment.reply_comment).user %><br>
#親コメントの内容を出力
<%= @comments.find(comment.reply_comment).content %><br>
----------------------<br>
<% end %>
#コメントを出力
<%= comment.content %>
# このコメントに対して投稿
<%= form_for [@product, @new_comments] do |f| %>
<ul class="collapsible">
<li>
<div class="collapsible-header"><i class="material-icons">message</i>コメントに返信をする</div>
<div class="collapsible-body">
<%= f.text_field :content %>
#ここ大事!hidden_fieldでフォーム無しに送信先コメントのidをreply_commentに追加
<%= f.hidden_field :reply_comment, :value => comment.id %>
<%= button_tag type:"submit", class: "waves-effect waves-light btn" do %>
<%= f.submit "投稿する" %>
<% end %>
</div>
</li>
</ul>
<% end %>
</div>
#コメント削除機能
<% if comment.user_id == current_user.id %>
<%= link_to product_comment_path(@product,comment), method: :delete , class: "waves-effect waves-light btn" do %>
<i class="fa fa-arrow-left"></i>
<span>コメント削除</span>
<% end %>
<% end %>
</li>
<% end %>
<%= f.hidden_field :reply_comment, :value => comment.id %>
こんな使い方、あるんですね。
#終わり
もう少し、動くだけでなくクエリや保守性を重要視できるコードを書きたいなあと思いました。
マサカリがあればお願いします。おそらく綺麗なコードではないと思いますので。