web系エンジニアを目指す私、siが学習のアウトプットをメインにプログラミングについての記事を書いていきます。

【Rails】コメント機能(投稿・編集・削除)の実装方法は?初心者にも分かりやすく解説

 
この記事を書いている人 - WRITER -

 

こんにちは!

web系エンジニアを目指して学習中のsiと申します^ ^

 

この記事の対象者

  • コメント投稿機能を実装したい方
  • コメント編集・削除機能を実装したい方

 

この記事は下記記事の続きになります!

【Rails】投稿編集(edit,update)、投稿削除(destroy)の実装!

 

今回実装するアクション

アクション名 使用方法
index リソースの一覧表示
show リソースの詳細表示
new リソースの新規作成
edit リソースの編集
create リソースを新規作成して保存する
update リソースの更新
destroy リソースの削除

 

基本的な7つのアクションについて気になる人は、以下の記事を参考にしてみてください!

※この記事で出てくる「%」はプロンプトなので実際に入力する必要はありません

 

マシンスペック

参考までに私のマシンスペックをご紹介しておきます。

  • macOS Big Sur 11.5.1
  • Macbook Pro(13-inch,2020,Four Thunderbolt 3 ports)
  • intel Core i5
  • メモリ 16GB
  • ストレージ 512GB
  • 使用シェル zsh

 

 

モデルの作成・編集

 

・Commentモデルの作成

% rails g model Comment user:references output:references body:string

 

・migrationファイルの編集

class CreateComments < ActiveRecord::Migration[6.1]
  def change
    create_table :comments do |t|
      t.references :user, null: false, foreign_key: true
      t.references :output, null: false, foreign_key: true
      t.string :body, null: false

      t.timestamps
    end
  end
end

 

・rails db:migrateを実行

% rails db:migrate

 

・Commentモデルの編集

# app/models/comment.rb

class Comment < ApplicationRecord
  validates :body, presence: true  #追加
  belongs_to :user
  belongs_to :output
end

validates :body, presence: trueと記述することで、空白データの保存を禁止します。

 

  • belongs_to :user
  • belongs_to :output

はモデル作成時にreferencesを指定することで自動的に記述されます。

 

referencesについては、こちらの記事で解説しています!

【Rails】referencesの使い方・外部キー制約/index/null: false

 

・Userモデルの編集

# app/models/user.rb

has_many :comments, dependent: :destroy  #追加

 

・Outputモデルの編集

# app/models/output.rb

has_many :comments, dependent: :destroy  #追加

dependent: :destroyと記述することで、親モデルが削除されたときに紐づく子モデルのレコードも削除されるようになります。

今回の場合だと、任意のUserモデル・Outputモデルのレコードが削除された時に、紐づくCommentモデルのレコードも削除されます。

 

ルーティングの編集

 

# config/routes.rb

resources :outputs do
  resources :comments, only: [:edit, :update, :create, :destroy]
end

outputsの中にネストして記述します。

 

ルーティングのネストについては、こちらの記事で解説しています!

【Rails】基本的なルーティングの書き方、ネスト・resourcesについても解説

 

投稿機能の実装

 

・commentsコントローラーの作成

% rails g controller comments

 

・commentsコントローラーの編集

# app/controllers/comments_controller.rb

class CommentsController < ApplicationController

  def create
    @output = Output.find(params[:output_id])
    @comment = current_user.comments.build(comment_params)
    if @comment.save
      redirect_to request.referer, notice: "アウトプットを投稿しました"
    else
      flash[:danger] = "投稿に失敗しました"
      redirect_back(fallback_location: root_path)
    end
  end

  private
  def comment_params
    params.require(:comment).permit(:body).merge(output_id: params[:output_id])
  end
end

 

・outputsコントローラーの編集

# app/controllers/outputs_controller.rb

def show
  @output = Output.find(params[:id])
  @comment = Comment.new #追加
  @comments = @output.comments.includes(:user) #追加
end

コメント投稿formはoutputのshowページに設置するため、comments#newへの記述をしません。そのため、outputs#showに必要な記述を行います。

 

redirect_back(fallback_location: root_path)と記載することで、遷移前のページに戻ります。

そうすることで、自分が投稿したコメントをすぐに確認出来ます。

 

・投稿formの作成

# app/views/outputs/show.html.erb

<h3>コメント一覧</h3>
<% @comments.each do |c| %>
  <%= c.body %>
<% end %>

<% if user_signed_in? %>
  <%= form_with model: [@output, @comment] do |f| %>
    <%= f.text_area :body, placeholder: "コメントする" %>
    <%= f.submit "SEND" %>
  <% end %>
<% end %>

form_withの引数に「@output」「@comment」の2つを渡しています。

 

form_withについては、こちらの記事で解説しています!

【form_with】基本的な書き方・複数のモデルを引数に指定(ネスト)する書き方

 

 

編集・削除機能の実装

 

・commentsコントローラーの編集

# app/controllers/comments_controller.rb

def edit
  @output = Output.find(params[:output_id])
  @comment = Comment.find(params[:id])
end

def update
  @output = Output.find(params[:output_id])
  @comment = Comment.find(params[:id])
  if @comment.update(comment_params)
    redirect_to output_path(@output), notice: "コメントを編集しました"
  else
    flash.now[:danger] = "編集に失敗しました"
    render 'edit'
  end
end

def destroy
  @comment = Comment.find(params[:id])
  @comment.destroy
  flash[:danger] = "コメントを削除しました"
  redirect_back(fallback_location: root_path)
end

 

・formパーシャルの作成

% touch app/views/comments/_form.html.erb

 

・editページの作成

% touch app/views/comments/edit.html.erb

 

・formパーシャルの編集

# app/views/comments/_form.html.erb

<%= form_with model: [@output, @comment] do |f|%>

  <div class="field">
    <%= f.label :body, "コメント編集" %></br>
    <%= f.text_field :body %>
  </div>

  <div class="submit">
    <%= f.submit "送信"%>
  </div>

<% end %>

 

・editページの編集

# app/views/comments/edit.html.erb

<%= render 'form' %>

 

・編集・削除ボタンの追加

# app/views/outputs/show.html.erb

<h3>コメント一覧</h3>
<% @comments.each do |c| %>
  <%= c.body %>
  <% if user_signed_in? %>  #追加
    <% if current_user.id == c.user_id %>  #追加
      <%= link_to "編集", edit_output_comment_path(@output, c) %>  #追加
      <%= link_to "削除", output_comment_path(@output, c), method: :delete %>  #追加
    <% elsif current_user.id == @output.user_id then %>  #追加
      <%= link_to "削除", output_comment_path(@output, c), method: :delete %>  #追加
    <% end %>  #追加
  <% end %>  #追加
<% end %>

 

ログインユーザーがコメント投稿者である場合、「編集ボタン」「削除ボタン」が表示されるようにしています。

 

また、ログインユーザーがアウトプット投稿者である場合は「削除ボタン」が表示されるようにしています。

 

つまり、アウトプット投稿者は自分のアウトプットに対する全てのコメントに対して「削除権限」があり、コメント投稿者は自分が投稿したコメントに対し、「編集権限」「削除権限」があります。

 

まず、<% if current_user.id == c.user_id %>でログインユーザーがコメント投稿者と同じであるかの判定を行います。

同じであった場合は、「編集ボタン」と「削除ボタン」を表示させます。

 

違った場合は、<% elsif current_user.id == @output.user_id then %>でログインユーザーとアウトプット投稿者が同じであるかの判定を行います。

同じであった場合は、「削除ボタン」を表示させます。

 

ログインユーザーがコメント投稿者でもアウトプット投稿者でもない場合は「編集ボタン」も「削除ボタン」も表示させません。非ログインユーザーの場合も同様です。

 

まとめ

 

  • モデル作成の時にreferencesを使うと便利
  • ルーティングはネストして書く
  • form_withには引数を2つ渡す

 

 

この記事を書いている人 - WRITER -

- Comments -

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


Copyright© .i DO WHAT I WANT , 2022 All Rights Reserved.