[Rails]コメント機能・ネスト構造まとめ
ビューで実際に書いたコード
コードが複雑になってしまったのでまとめます。
<ul>
コメント件数:<%= @task.task_comments.count %>
<p></p>
<!-- 投稿されたコメントを表示 -->
<% @task.task_comments.each do |task_comment| %>
<li class="comment">
<div class="comment-container">
<div class="comment-image">
<% if task_comment.user.image.attached? %>
<%= image_tag task_comment.user.image, size: "40x40", alt: "#{task_comment.user.name}のプロフィール画像" %>
<% else %>
<%= image_tag "no_image.jpg", size: "40x40", alt: "デフォルトプロフィール画像" %>
<% end %>
</div>
<div class="comment-content">
<p class="comment-text"><%= task_comment.comment %></p>
<span class="task-meta">
<%= task_comment.user.name %>
<%= task_comment.created_at.in_time_zone('Tokyo').strftime('%m月%d日 %H:%M') %>
<% if task_comment.user == current_user %>
<%= link_to "削除", task_task_comment_path(task_comment.task, task_comment), method: :delete %>
<% end %>
</span>
</div>
<br>
</div>
</li>
<hr size="10">
<% end %>
<!-- コメント投稿フォーム -->
<%= form_with model:[@task, @task_comment] do |f| %>
<%= f.text_area :comment, rows: 3, style: "width: 550px;", placeholder: "コメントを入力" %>
<br>
<%= f.submit "送信", class: "submit-btn" %>
<% end %>
</ul>
ルーティング(ネスト構造)
resources :tasks, only: [:new, :create, :index, :show, :edit, :update, :destroy] do
resources :task_comments, only: [:create, :destroy]
end
resources
は、Railsでルーティングを簡潔に定義するためのメソッド。
tasks
の中にtask_comments
がある。どのタスクに紐づいたコメントか、URLで判別できるようになる。これをネスト構造と呼ぶ。
ネストされたresources :task_comments
の動作
ネストされたresources :task_comments
を使うと、タスクに紐づいたコメントに関するルーティングが生成される。
HTTPメソッド | パス | コントローラ#アクション | 用途 |
---|---|---|---|
POST | /tasks/:task_id/task_comments | task_comments#create |
特定のタスクにコメントを追加する |
DELETE | /tasks/:task_id/task_comments/:id | task_comments#destroy |
特定のタスクのコメントを削除する |
:task_id
ネストされたルーティングでは、親リソース(ここではtasks
)のIDがURLに含まれる。この:task_id
が、コメントがどのタスクに属しているかを特定するために使われる。
コントローラ
class Public::TasksController < ApplicationController
def show
@task = Task.find(params[:id])
@task_comment = TaskComment.new
end
# ストロングパラメータ
def task_params
params.require(:task).permit(:title, :keyword1, :keyword2, :keyword3)
end
end
@task
はタスクコントローラで定義されている。
「@task = Task.find(params[:id])」部分は、Taskモデルのデータベースからidに該当する特定のタスクを取得し、その結果を@taskというインスタンス変数に代入している。
これにより、@task
で投稿をデータベースから情報を取得できる。
また、@task_comment
は新しく作成したTaskCommentのオブジェクトを格納している。
paramsについて
params
とは、Railsにおいてリクエスト(ユーザーが送ったデータ)を受け取るためのオブジェクト。
フォーム送信やURLのパス・クエリパラメータから値を取得する際に使用する。
require
モデル名を指定して送られてくるデータを絞り込む。(タスクコントローラ内では、Taskモデルに関連するデータしか操作されない)
permit
requireで絞り込んだものから、保存するカラムを指定する。
# ストロングパラメータ
def task_params
params.require(:task).permit(:title, :keyword1, :keyword2, :keyword3)
end
コメントの表示部分
<% @task.task_comments.each do |task_comment| %>
- @taskで投稿IDを取得。
- @task.task_comments=その投稿IDに含まれる各コメントを1つずつ「task_comment」変数(||に挟まれてる部分)に取り出し、以下の処理を繰り返している。
コメント本文・画像・投稿者名・日時の表示部分
<% if task_comment.user.image.attached? %>
<%= image_tag task_comment.user.image, size: "40x40", alt: "#{task_comment.user.name}のプロフィール画像" %>
<% else %>
<%= image_tag "no_image.jpg", size: "40x40", alt: "デフォルトプロフィール画像" %>
<% end %>
<p class="comment-text"><%= task_comment.comment %></p>
<%= task_comment.user.name %>
<%= task_comment.created_at.in_time_zone('Tokyo').strftime('%m月%d日 %H:%M') %>
task_comment.○○(comment・user.nameなど表示させたいもの)
で、表示させる。
↑の「コメントの表示部分」の |task_comment|
で、「task_comment」にコメントを1つずつ格納しているので、「task_comment」を使えば投稿者名などの情報が表示できる。
コメント削除リンク
<% if task_comment.user == current_user %>
<%= link_to "削除", task_task_comment_path(task_comment.task, task_comment), method: :delete %>
<% end %>
-
task_task_comment_path(task_comment.task, task_comment)
は、上記ルーティングより、下記のURLを生成する。/tasks/:task_id/task_comments/:id
-
task_comment.task
で親リソース(タスク)のIDを指定。 -
task_comment
で削除対象のコメントのIDを指定。
-
-
method: :delete
を指定しているため、このリンクをクリックすると削除リクエストが送信されます。
コメント投稿フォーム
<%= form_with model: [@task, @task_comment] do |f| %>
- form_withを使用して、コメントを投稿するフォームを作成。
form_withは、Ruby on Railsにおいてフォームを作成するためのヘルパーメソッド。
ユーザーからデータを入力して送信するためのHTMLフォームを簡単に作成できる。 -
modelオプション は、フォームが操作するデータ(親リソースと子リソース)をRailsに伝えるために書いている。
つまり、「@task(一個一個のタスク)に関連付けた@task_comment(タスクのコメント)を送信するフォームです」という意味。
ルーティングから、送信先は次のようになる。
POST /tasks/:task_id/task_comments
ネスト構造から次のようなデータが送信される。
params = {
task_id: "1", # URLから取得されたタスクID(親リソース)
task_comment: { # フォームで入力されたコメント内容(子リソース)
comment: "ユーザーが入力したコメント"
}
}
コメント投稿の流れ
以下のフォームの場合・・・
<%= form_with model: [@task, @task_comment], local: true do |f| %>
<%= f.text_area :comment, placeholder: "コメントを入力" %>
<%= f.submit "送信" %>
<% end %>
生成されるHTMLフォームは、下記のようになる。
<form action="/tasks/1/task_comments" method="post">
<textarea name="task_comment[comment]" placeholder="コメントを入力"></textarea>
<input type="submit" value="送信">
</form>
URL
POST /tasks/1/task_comments
リクエストデータ(実際にサーバに送信されるデータ)
{
task_id: "1", # URLから取得された親リソースID
task_comment: { # フォームのフィールドデータ
comment: "ユーザーが入力したコメント"
}
}
参考文献
pramasについて
ネスト構造について
Discussion