コメント機能実装
初めましてこんにちは!すんぎぃです。
SoundReviewというアプリができるまでの流れをやっています。
今回は、コメント機能の実装方法について話していきます。
1.目的
レビューに対する意見を言えるようにする。
2.使ったgem・API
なし
3.方法
①terminalで以下のコマンドを実行してモデルを作成します。
%rails g model comments
②生成されたマイグレーションファイルを以下のように編集します。
class CreateMessages < ActiveRecord::Migration[6.0]
def change
create_table :messages do |t|
t.text :comment
t.string :audiocomment
t.references :user, null: false, foreign_key: true
t.references :item, null: false, foreign_key: true
t.timestamps
end
end
end
コメントは、「誰が投稿したコメントなのか」がわかる必要があるため、結びつくユーザーのidを保存します。
ここでは、そのidを保存するカラム名をuserとしています。
また、コメントは「どのレビューに対してのコメントなのか」を明示する必要があるため結びつくレビューのidを保存するカラムをitemとしています。
③以下のコマンドを実行してテーブルを作成します。
%rails db:migrate
④アソシエーション、バリデーションを定義します。
○comment.rbを以下のように編集します。
class Comment < ApplicationRecord
belongs_to :item
belongs_to :user
mount_uploader :audiocomment, AudiofileUploader
validates :comment, presence: true, unless: :audiocomment?
validates :audiocomment, presence: true, unless: :comment?
end
コメントは、一人のユーザー、一つのレビューに所属するので、belongs_to :モデル単数形と記述してアソシエーションを定義します。
音声コメントも文字コメントもどちらもない時には、保存されないようにバリデーションをかけています。
○user.rbを以下のように編集します。
##省略
has_many :comments, dependent: :destroy
##省略
ユーザーは、複数のコメントを投稿することができるので、has_many :モデル複数形と記述をしアソシエーションをかけています。
また、dependent: :destroyとし、ユーザーの削除が行われた場合にそのユーザーが投稿したコメントも全て削除されるようにしています。
○items.rbを以下のように編集します。
##省略
has_many :messages, dependent: :destroy
##省略
レビューは、複数のコメントを所有することができるので、has_many :モデル複数形と記述としアソシエーションをかけています。
また、dependent: :destroyとし、レビューの削除が行われた場合にそのレビューに投稿されたコメントも全て削除されるようにしています。
⑤routes.rbを以下のように編集します。
Rails.application.routes.draw do
mount RailsAdmin::Engine => '/admin', as: 'rails_admin'
devise_for :users
root to: 'items#index'
resources :items do
resources :comments, only: [:new, :create]
collection do
get :search
end
end
resources :items
resources :users, only: [:show,:index,:edit,:update,:destroy]
コメントの作成を行うのでcreateアクションを加えます。
ルーティングのネストすることでどのレビューに対するコメントなのかid情報をつけることができます。
ルーティングをネストさせる一番の理由は、アソシエーション先のレコードのidをparamsに追加してコントローラーに送ることです。
②commentsコントローラーを作成します。
terminalにて以下のコマンドを実行します。
%rails g controller comments
③ comments_controller.rbを以下のように編集します。
class MessagesController < ApplicationController
def create
@item = Item.find(params[:item_id])
@message = @item.messages.new(message_params)
if @message.save
redirect_to "/items/#{@message.item.id}"
end
end
private
def message_params
params.require(:message).permit(:comment, :audiocomment).merge(user_id: current_user.id, item_id: params[:item_id])
end
end
④app/views/items/show.html.erbを以下のように編集します。
<div class="comment-box">
<% if user_signed_in? %>
<h2 class="items-sell-title">コメントを入力</h2>
<%= form_with model:[@item,@message], local: true do |f| %>
<div class="comment-explain">
<div class="weight-bold-comment w-comment">
・文字コメント
</div>
<%= f.text_area :comment, class:"items-comment", id:"comment-info"%>
<div class="weight-comment w-comment">
・音声コメント
</div>
<%= f.file_field :audiocomment , class:"sound-comment" %>
</div>
<div class="sell-btn-contents">
<%= f.submit "投稿する" ,class:"comment-btn" %>
</div>
<%end%>
<% else %>
<strong><p>※ コメントの投稿には新規登録/ログインが必要です </p></strong>
<% end %>
<%if @mess.present?%>
<tbody id="message">
<%= render 'messages/index', messages: @messages %>
</td>
<%else%>
<h2 class="items-comment-title">コメント</h2>
<%end%>
</div>
ログインしていない状態では、投稿フォームが表示されないようにしています。
⑤app/views/commentsディレクトリに_index.html.erbファイルを作成します。そして以下のように編集します。
<div class="comments">
<h4><コメント一覧></h4>
<div class="comment" id="messages">
<% messages.each do |message| %>
<p>
<% if message.comment.present?%>
<div class="comment-profile">
<div class="profil">
<% if @item.user.image.attached? %>
<%=link_to user_path(message.user.id),class:"user-icon2" do %>
<%= image_tag @item.user.image, class: "user-icon2" %>
<%end%>
<% else %>
<%=link_to user_path(@item.user.id) ,class:"user-icon2" do %>
<%= image_tag "willy.png", alt: "user-icon", class: "user-icon2" %>
<%end%>
<% end %>
</div>
<div class="name-profil">
<%= link_to message.user.nickname, user_path(message.user.id) ,class: "message-nickname" %>
</div>
</div>
<div class="m-comment">
<%= message.comment %><br/>
</div>
<%end%>
</p>
<% end %>
</div>
</div>
<div class="comments2">
<h4><音声コメント一覧></h4>
<div class="comment2" id="messages">
<% messages.each do |message| %>
<p>
<% if message.audiocomment.present?%>
<div class="comment-profile">
<div class="profil">
<% if @item.user.image.attached? %>
<%=link_to user_path(message.user.id),class:"user-icon2" do %>
<%= image_tag @item.user.image, class: "user-icon2" %>
<%end%>
<% else %>
<%=link_to user_path(@item.user.id) ,class:"user-icon2" do %>
<%= image_tag "willy.png", alt: "user-icon", class: "user-icon2" %>
<%end%>
<% end %>
</div>
<div class="name-profil">
<%= link_to message.user.nickname, user_path(message.user.id) ,class: "message-nickname" %>
</div>
</div>
<div class="auc">
<audio src= "<%= "#{message.audiocomment}" %>" controls="">
</div>
<%end%>
</p>
<% end %>
</div>
</div>
⑥items_controller.rbを以下のように編集します。
##省略
def show
@message = Message.new
@messages = @item.messages.includes(:user).order('created_at DESC')
@messages.each do |message|
@mess = message
end
end
##省略
4.まとめ
これにて完成です。
以下のように表示されたらOK!!です。
ありがとうございました。
この記事が気に入ったらサポートをしてみませんか?