見出し画像

コメント機能実装

初めましてこんにちは!すんぎぃです。
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!!です。
ありがとうございました。

画像1


この記事が気に入ったらサポートをしてみませんか?