🥕

Rails コメント機能

2023/04/19に公開

「コメント機能」の作成

投稿された画像に対して、コメントをつけることができる機能を実装
それぞれ新たなモデルを作成し、UserモデルとPostImageモデルに関連付ける!!(1対Nの関係)

必要なファイルを準備

作成するモデル・テーブル

  • PostCommentモデル
  • post_commentsテーブル

作成するコントローラ

  • post_commentsコントローラ

編集するファイル

  • post_imagesコントローラ
  • post_images/showのビュー
  • ルーティング設定ファイル

コメント保存用のテーブルを設計

「誰の投稿か」「どの画像に投稿したのか」がわかるようにするため、user_idとpost_image_idを持たせる!

カラム名 データ型 カラムの説明
id integer コメントごとのID
comment text コメント本文
user_id integer コメントしたユーザのID
post_image_id integer コメントされた投稿画像のID

「PostComment」モデルを作成

rails g model PostComment comment:text user_id:integer post_image_id:integer

マイグレーションでデータベースへ反映

rails db:migrate

3つのモデルの関係性を把握

PostCommentモデルは、user_idやpost_image_idと関連付ける必要がある。

Userモデル/PostImageモデル
1人のユーザが複数の画像を投稿できる、1対Nの関係

PostImageモデル/PostCommentモデル
1つの投稿画像に対して、複数のコメントを設定できる、1対Nの関係

Userモデル/PostCommentモデル
1人のユーザが複数のコメントを行えるので、1:Nの関係

1:Nの関連付けをモデルに実装

1:Nの関係(アソシエーション)を、機能として実装する!

UserモデルとPostCommentモデルを関連付け

app/modelsフォルダのuser.rbファイル

has_many :post_comments, dependent: :destroy

dependent: :destroyは、has_manyで使えるオプション
1:Nの関係において、「1」のデータが削除された場合、関連する「N」のデータも削除される設定!

PostImageモデルとPostCommentモデルを関連付け

app/models/post_image.rb

has_many :post_comments, dependent: :destroy

UserモデルとPostCommentモデルを関連付け

app/models/post_comment.rb

belongs_to :user
belongs_to :post_image

Controllerの作成

rails g controller post_comments

コメント投稿機能

コメント機能では投稿機能・投稿削除機能の二つを実装!

まずはコメント投稿機能から
👇

Routing

コメントは、投稿画像に対してコメントされるため、
以下のように親子関係になる!

config/routes.rb

resources :post_images, only: [:new, :create, :index, :show, :destroy] do
    resources :post_comments, only: [:create]
end

このようなルーティングが作成される!

post_image_post_comments POST   /post_images/:post_image_id/post_comments(.:format)     post_comments#create

親のresourcesで指定したコントローラ名に、子のresourcesで指定したコントローラ名が続くURLが生成されるのが確認できる🙆🏻‍♀️
ネストしたURLを作成することでparams[:post_image_id]でPostImageのidが取得できるようになる!!

Controller

app/controllers/post_comments_controller.rb

def create
    post_image = PostImage.find(params[:post_image_id])
    comment = current_user.post_comments.new(post_comment_params)
    comment.post_image_id = post_image.id
    comment.save
    redirect_to post_image_path(post_image)
end

private

def post_comment_params
   params.require(:post_comment).permit(:comment)
end

ちなみにこの記述は

comment = current_user.post_comments.new(post_comment_params)

この記述を省略したもの

comment = PostComment.new(post_comment_params)
comment.user_id = current_user.id

コメントを投稿するためのインスタンス変数を定義

app/controllers/post_images_controller.rb

def show
  @post_comment = PostComment.new
end

View

投稿画像の詳細画面で、コメントを投稿できるようにし、投稿画像へのコメント、コメント数も表示させる!

app/views/post_images/show.html.erb

<div>
  <p>コメント件数:<%= @post_image.post_comments.count %></p>
  <% @post_image.post_comments.each do |post_comment| %>
    <p><%= image_tag post_comment.user.get_profile_image(100,100) %></p>
    <%= post_comment.user.name %>
    <%= post_comment.created_at.strftime('%Y/%m/%d') %><%= post_comment.comment %>
  <% end %>
</div>
<div>
  <%= form_with model: [@post_image, @post_comment] do |f| %>
    <%= f.text_area :comment, rows: '5', placeholder: "コメントをここに" %>
    <%= f.submit "送信する" %>
  <% end %>
</div>

form_withに対して、[@post_image,@post_comment]のように、配列でインスタンス変数を2つ指定している点に注意
コメントは、post_imageに結びついたpost_commentであるため、2つ用意する必要があり、
post_commentをcreateするためのリクエストは、ルーティングもネスト(親子関係)しているため、上記2つの情報が必要になる!!!

コメント件数の表示を記述

2つのファイルに、コメント件数を表示する記述を追加

app/views/post_images/index.html.erb

<p><%= link_to "#{post_image.post_comments.count} コメント", post_image_path(post_image.id) %></p>

app/views/users/show.html.erb

<p><%= link_to "#{post_image.post_comments.count} コメント", post_image_path(post_image.id) %></p>

動作を確認

実際にコメントを入力して確かめる。

コメント削除機能

post_comments_controller.rbにdestroyアクションを作成していく!

Routing

config/routes.rb

resources :post_images, only: [:new, :create, :index, :show, :destroy] do
    resources :post_comments, only: [:create, :destroy]  
end

Controller

destoryアクションを作成

app/controllers/post_comments_conteoller.rb

def destroy
    PostComment.find(params[:id]).destroy
    redirect_to post_image_path(params[:post_image_id])
 end 

View

削除ボタンを表示させる

app/views/post_images/show.html.erb

 <% if post_comment.user == current_user %>
      <%= link_to "削除", post_image_post_comment_path(post_comment.post_image, post_comment), method: :delete %>
 <% end %>

コメントしたものがログインユーザーのものであれば削除ボタンを表示して、削除できるようにした!
削除後は投稿詳細へリダイレクトされる🙆🏻‍♀️

動作を確認

コメントの削除ボタンを押して確認

応用編

空のコメントは投稿できない

モデル

validates :comment, presence: true

コメント数の表示

ビュー

コメント数: <%= @book.book_comments.count %>

投稿に対するコメント一覧を表示

ビュー

<% book.book_comments.each do |book_comment| %>
  <%= book_comment.comment %>
<% end %>

自分のコメントしか削除できない

ビュー

<% if book_comment.user == current_user %>
   <%= link_to "Destroy", book_book_comment_path(book, book_comment), method: :delete, class: "btn btn-danger pull-right" %>
<% end %>

コメント, コメント削除後は行う前の画面に遷移

それぞれのアクションに

redirect_to request.referer

redirect_toメソッドの一種で、このメソッドは、ユーザーが直前にアクセスしたページにリダイレクトするために使用される!


今一度コメント機能の削除について復習!
間違っているところがあればぜひ教えてください!
今日はここまで!

Discussion