LoginSignup
31
36

More than 3 years have passed since last update.

Railsでコメントに対する返信機能を実装した!

Last updated at Posted at 2018-05-11

実装内容

今回はコメントに対する返信機能の作成です
- 返信テーブルはコメントテーブルと同じです。
- コメントの返信フォームからコメントを送信すると、そのコメントに対しての返信になる
- コメント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  %>

こんな使い方、あるんですね。

結果

スクリーンショット 2018-05-11 21.28.42.png

スクリーンショット 2018-05-11 22.40.11.png

終わり

もう少し、動くだけでなくクエリや保守性を重要視できるコードを書きたいなあと思いました。
マサカリがあればお願いします。おそらく綺麗なコードではないと思いますので。

31
36
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
36