🐷

[Rails]コメント機能・ネスト構造まとめ

2025/01/28に公開

ビューで実際に書いたコード

コードが複雑になってしまったのでまとめます。

<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