投稿詳細ページにコメントフォームを追加しよう
学習の目標
本章では、以下の内容を学習します。
- 投稿詳細ページにコメントフォームを追加する方法を習得する
- ネストされたリソース向けのフォーム作成方法を理解する
- ログイン状態に応じた条件分岐表示の実装方法を学ぶ
- フォームのスタイリングとユーザー体験向上のテクニックを理解する
はじめに
前回のレッスンでは、コメント機能のためのルーティングを設定しました。これにより、URLの構造でコメントと投稿の関係が表現できるようになりました。しかし、まだユーザーがコメントを投稿するための入力フォームがありません。
今回は、投稿詳細ページにコメント投稿用のフォームを追加していきます。ユーザーがコメントを入力できるインターフェースを作成することで、コミュニケーション機能の第一歩が完成します。
コメントフォームは、ログインしているユーザーのみが使用できるように制限します。これにより、ログインしていないユーザーには「コメントを投稿するにはログインしてください」というメッセージを表示し、ユーザー登録やログインを促進することができます。
投稿詳細ページの確認
まずは現状の投稿詳細ページを確認しておきましょう。現在は、投稿のタイトルと内容、および投稿者の情報だけが表示されています。これに、コメントフォームと後々コメント一覧を追加していきます。
コントローラーの修正
コメントフォームを追加するにあたり、まずは PostsController
の show
アクションを修正して、新しいコメントのためのインスタンス変数を追加します。
app/controllers/posts_controller.rb
の show
アクションを以下のように修正してください。
def show @post = Post.find_by(id: params[:id]) @comment = Comment.new # 新規コメント用のインスタンスを作成end
この変更により、投稿詳細ページでコメントフォームに必要な @comment
インスタンス変数が利用可能になります。これは空の新しい Comment
オブジェクトで、フォームの初期状態として使用されます。
コメントフォームの追加
次に、投稿詳細ページにコメントフォームを追加します。app/views/posts/show.html.erb
を開き、以下のように修正してください。
<div class="space-y-6 w-3/4 max-w-lg"> <label class="block text-xl font-bold text-gray-700">学習ログ詳細</label>
<div class="items-center justify-center"> <div tabindex="0" aria-label="card 1" class="focus:outline-none mb-7 bg-white p-6 shadow rounded"> <div class="flex items-center border-b border-gray-200 pb-6"> <div class="flex items-start justify-between w-full"> <div class="pl-3"> <h3 class="focus:outline-none text-lg font-medium leading-5 text-gray-800"><%= @post.title %></h3> <p class="focus:outline-none text-sm leading-normal pt-2 text-gray-500">by <%= link_to @post.user.nickname, user_path(@post.user), class: "hover:text-indigo-600 hover:font-bold" %></p> </div> <% if user_signed_in? %> <% if @post.user_id == current_user.id %> <%= button_to "削除", post_path(@post), method: :delete, class: "text-sm bg-transparent hover:bg-blue-500 text-blue-700 hover:text-white py-1 px-3 border border-blue-500 hover:border-transparent rounded hover:cursor-pointer" %> <% end %> <% end %> </div> </div> <div class="px-2"> <p class="focus:outline-none text-sm leading-5 py-4 text-gray-600"><%= @post.content %></p> </div> </div>
<!-- コメントフォームを追加 --> <div class="bg-white p-6 shadow rounded mb-7"> <h4 class="text-lg font-medium text-gray-800 mb-4">コメントを投稿する</h4>
<% if user_signed_in? %> <%= form_with(model: [@post, @comment], url: post_comments_path(@post), class: "space-y-4") do |f| %> <div> <%= f.text_area :content, rows: 3, placeholder: "コメントを入力してください...", class: "shadow-sm focus:ring-indigo-500 focus:border-indigo-500 mt-1 block w-full sm:text-sm border border-gray-300 rounded-md p-2" %> </div> <div class="text-right"> <%= f.submit "コメントする", class: "inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" %> </div> <% end %> <% else %> <div class="bg-gray-100 p-4 rounded-md text-center"> <p class="text-gray-600">コメントを投稿するには<%= link_to "ログイン", new_user_session_path, class: "text-indigo-600 hover:text-indigo-800 font-medium" %>してください。</p> </div> <% end %> </div>
<!-- ここにコメント一覧を表示(次のレッスンで実装) -->
</div></div>
このコードでは、投稿詳細カードの下に新しいセクションを追加して、コメント投稿フォームを表示しています。主要な部分について詳しく説明します。
※ついでに少しコードを整理して、HTMLタグ構造を整えている部分もありますが、全体の流れは変わっていません。
ネストされたリソースのフォーム
コメントフォームの核となるのは、form_with
ヘルパーメソッドです。
<%= form_with(model: [@post, @comment], url: post_comments_path(@post), class: "space-y-4") do |f| %>
いくつかポイントを解説します。
model: [@post, @comment]
- 親リソース(投稿)と子リソース(コメント)を配列で指定しています。これは、ネストされたリソースのフォームを作成する際の標準的な書き方です。url: post_comments_path(@post)
- フォームの送信先URLを明示的に指定しています。これは/posts/:post_id/comments
のようなパスを生成します。class: "space-y-4"
- Tailwind CSS のクラスを指定して、フォーム要素間の間隔を調整しています。
フォーム内では、text_area
フィールドを使ってコメント内容の入力欄を作成し、submit
ボタンでフォームの送信を行います。
条件分岐による表示制御
このコードでは、ユーザーのログイン状態に応じて表示内容を切り替えています。
<% if user_signed_in? %> <!-- コメントフォーム表示 --><% else %> <div class="bg-gray-100 p-4 rounded-md text-center"> <p class="text-gray-600">コメントを投稿するには<%= link_to "ログイン", new_user_session_path, class: "text-indigo-600 hover:text-indigo-800 font-medium" %>してください。</p> </div><% end %>
ログインしているユーザーには通常のコメントフォームを表示し、ログインしていないユーザーには「コメントを投稿するにはログインしてください」というメッセージとログインへのリンクを表示します。これにより、未ログインのユーザーに対してもユーザー登録を促すことができ、アプリケーションの活性化に繋がります。
このような条件分岐は、ユーザー体験を向上させるために非常に重要です。ユーザーの状態に応じて適切なインターフェースを提供することで、ユーザーフレンドリーなアプリケーションになります。
動作確認
ここまでの実装で、投稿詳細ページにコメントフォームが追加されたはずです。実際にアプリケーションを起動して確認してみましょう。
$ bin/dev
ブラウザで投稿詳細ページ (http://localhost:3000/posts/1
など) にアクセスして、以下の点を確認してください。
ログインしている場合
- コメントフォームが表示されるか
- フォームに内容を入力できるか
- ボタンのスタイルが適切に表示されるか
ログアウトした場合
- ログインを促すメッセージが表示されるか
- ログインへのリンクが機能するか
ただし、まだコメント投稿機能自体は実装していないので、「コメントする」ボタンをクリックしてもエラーになります。次のレッスンで、実際のコメント投稿機能を実装していきます。
変更をコミット
ここまでの変更をコミットしておきましょう。
$ git add .$ git commit -m "投稿詳細ページにコメントフォームを追加"$ git push
まとめ
本章では、投稿詳細ページにコメントフォームを追加する方法を学びました。ネストされたリソースのフォーム作成方法や、ログイン状態に応じた条件分岐表示など、実践的な技術を習得しました。
具体的には、以下の内容を実装しました。
- 投稿詳細ページにコメント投稿用のフォームを追加
- ネストされたリソースを扱うためのフォーム設定
- ログイン状態に応じた表示切替による使いやすいUI
コメントフォームの見た目が整いましたが、まだ実際のコメント投稿機能は実装していません。次のレッスンでは、コメントフォームから送信されたデータを処理し、実際にコメントを保存する機能を実装していきます。
この後、コメント一覧表示機能も追加して、ユーザー間のコミュニケーションを可能にしていきましょう。
Basicプランでより詳しく学習
この先のコンテンツを読むにはBasicプラン以上が必要です。より詳細な解説、実践的なサンプルコード、演習問題にアクセスして学習を深めましょう。