メル○リのようなフリマアプリ制作にて、商品に対してコメント投稿機能を実装しました。その手順について解説します。ここでの目標はコメント投稿後に画面を更新するとコメントが投稿される同期通信であり、下記完成画像の非同期でコメントが反映される実装は次の記事にて紹介します。
完成画像
実装手順
以下の手順で実装していきます。
❶ DB設計
❷ Commentモデルの作成
❸ ルーティング設定
❹ Commentsコントローラの作成 / Itemsコントローラの編集
❺ コメント投稿フォームの作成
❻ コメント一覧表示欄の作成
❶ DB設計
コメント機能に関係のないテーブルは省いています。
❷ Commentモデルの作成
$ rails g model comment
マイグレーションファイル
class CreateComments < ActiveRecord::Migration[5.2]
def change
create_table :comments do |t|
t.integer :user_id, null: false
t.integer :item_id, null: false
t.text :text, null: false
t.timestamps
end
end
end
$ rails db:migrate
Commentsテーブルが作成されたか確認します。
モデルにアソシエーションの記載
app/models/comment.rb
class Comment < ApplicationRecord
belongs_to :user
belongs_to :item
end
コメントは一人のユーザと一つの商品に紐づいているので、belongs_to:モデル単数形になります。
app/models/item.rb
class Item < ApplicationRecord
略
has_many :comments, dependent: :destroy
略
end
商品は複数のコメントを所有できるので、has_many:複数形になります。
app/models/user.rb
class User < ApplicationRecord
略
has_many :comments, dependent: :destroy
略
end
ユーザは複数のコメントを投稿できるので、has_many:複数形になります。
❸ ルーティング設定
createアクションをitemsからネストします。
config/routes.rb
resources :items do
略
resources :comments, only: :create
略
end
発行されるルーティングパスは以下の通りです。商品ごとのitem_idに紐づいたcommentsのパスになります。
Prefix Verb URI Pattern Controller#Action
item_comments POST /items/:item_id/comments(.:format) comments#create
❹ Commentsコントローラの作成 / Itemsコントローラの編集
$ rails g controller comments
createアクションを設定します。
app/controllers/comments_controller.rb
class CommentsController < ApplicationController
def create
@item = Item.find(params[:item_id])
comment = Comment.new(comment_params)
if comment.save
redirect_to item_path(@item)
else
flash.now[:alert] = 'コメントを入力してください。'
end
end
private
def comment_params
params.require(:comment).permit(:text).merge(user_id: current_user.id, item_id: params[:item_id])
end
end
createアクションでcommentをDBに保存できたらitemsコントローラのshowアクションを実行するためにprefixでパス「item_path」を記述します。itemのidが必要なので、ストロングパラメータで変数commentに代入します。
今回はif文でcomment.saveしているのでオブジェクト作成だけのComment.newですが、DB保存まで行うComment.createメソッドでも作成できます。
app/controllers/items_controller.rb
def show
略
@comment = Comment.new
@comments = @item.comments.order(created_at: :desc)
end
comment#createにアクションを飛ばしたいので、@comment = Comment.newでインスタンスを作成します。
投稿されたコメントは降順にするためorderメソッドを使用します。
❺ コメント投稿フォームの作成
app/views/items/show.html.haml
.itemcomment__box__content
- if current_user
= form_with(model:[@item, @comment], class: "message-form") do |form|
%p 相手のことを考え丁寧なコメントを心がけましょう。不快な言葉遣いなどは利用制限や退会処分となることがあります。
= form.text_area :text, {class: "textbox"}
%input{type:"submit", class:"form__submit", value:"コメントする"}
- else
%strong
%p ※※※ コメントの投稿には新規登録/ログインが必要です ※※※
if current_userとして、ログインしていない状態では投稿フォームが表示されないようにします。
❻ コメント一覧表示欄の作成
app/views/items/show.html.haml
.itemcomment__box__content__comment
%p < コメント一覧 >
- if @comments
.itemcomment__box__content__comment__member
- @comments.each do |comment|
.itemcomment__box__content__comment__member__list
= comment.user.nickname
%strong :
= comment.text
if @commentとして、@commentが空の場合でもエラーが起きないようにしています。