🍎

【Rails】コメント機能実装(同期)

2023/07/25に公開
  • アプリケーション作成済
  • 「Userモデル」「Bookモデル」「BookCommentモデル」を使用して実装
  • コメント件数、コメント投稿内容、コメント投稿フォームを実装
  • 完成イメージ ↓

altテキスト

1.BookCommentモデル、book_commentsテーブルを作成

ターミナル
$ rails g model BookComment comment:text user_id:integer book_id:integer

実行結果として下記が表示されればOK!

ターミナル
Running via Spring preloader in process 26537
      invoke  active_record
      create    db/migrate/20230725044406_create_book_comments.rb
      create    app/models/book_comment.rb
      invoke    test_unit
      create      test/models/book_comment_test.rb
      create      test/fixtures/book_comments.yml
ターミナル
$ rails db:migrate
  • ここまでで「BookCommentモデル」「book_commentsテーブル」が生成された
  • 「comment:text」=コメント用のカラム
  • 「user_id:integer」「book_id:integer」=user_id,book_idを外部キーとして生成

2.アソシエーションを設定

  • 1人のUserはコメントをたくさん持っている(複数の投稿にコメントすることができる)
  • 1つのbookはたくさんのUserからのコメントを持っている
    ・・・つまり、UserとBookは「 多:多 」の関係性であるため、「 1:N 」の関係性を作れるように「中間テーブル」を作成する必要がある。

中間テーブルとして「book_commentsテーブル」を作成し、「user_id」と「book_id」を結びつける。

app/models/user.rb
class User < ApplicationRecord
:
  has_many :books, dependent: :destroy
  has_many :book_comments, dependent: :destroy  ←これを追記!
  • 「dependent: :destroy」=対象のUserが削除されたら、関連するBookCommentも削除される
app/models/book.rb
class Book < ApplicationRecord
:
  belongs_to :user
  has_many :book_comments, dependent: :destroy  ←これを追記!
  • 「dependent: :destroy」=対象のBookが削除されたら、関連するBookCommentも削除される
app/models/book_comments.rb
class BookComment < ApplicationRecord
  belongs_to :user
  belongs_to :book
end

3.ルーティング設定

app/config/routes.rb
Rails.application.routes.draw do
:
:
 resources :books, only: [:new, :create, :index, :show, :edit, :update, :destroy] do
    resources :book_comments, only: [:create, :destroy]
 end
  • Userがコメントしたのは、どの「本」なのか。がわかるように、booksコントローラーのルーティングにネストさせる
  • createアクション(コメントを投稿)、destroyアクション(コメントを削除)を記述

$ rails routesの結果

ターミナル
book_book_comments POST  /books/:book_id/book_comments(.:format)  book_comments#create
book_book_comment DELETE /books/:book_id/book_comments/:id(.:format)  book_comments#destroy
  • ルーティングに「:book_id」が含まれている!
  • params[:book_id]でBookのidが取得可能

4.コントローラー作成

ターミナル
$ rails g controller book_comments

ルーティングで設定したcreate、destroyアクションを記述

app/controllers/book_comments_controller.rb
class BookCommentsController < ApplicationController
  def create
  end
  
  def destroy
  end
end

5.アクションを実装

app/controllers/book_comments_controller.rb
class BookCommentsController < ApplicationController
  def create
    book = Book.find(params[:book_id])  #本のidを取得
    comment = BookComment.new(book_comment_params) #ストロングパラメータのbook_comment_paramsを使ってnew(新規投稿)用の空のカラムを準備
    comment.user_id = current_user.id #ログインしているユーザーのidを代入
    comment.book_id = book.id #コメントを投稿する本のidを取得
    comment.save #コメントを保存
    redirect_to request.referer #アクション実行後に同ページに遷移(ページは変わらない)
  end
  
  def destroy
    BookComment.find(params[:id]).destroy #本のidを取得
    redirect_to request.referer
  end
  
  private
  
  def book_comment_params
    params.require(:book_comment).permit(:comment)
  end
  
end

books/showページに実装するため、books_controller/showアクションに、コメントを投稿するための記述をする

app/controllers/books_controller.rb
:
  def show
  :
    @book = Book.find(params[:id])
    @book_comment = BookComment.new
  end
:
  

6.ビューを作成

投稿詳細ページに「コメント数」「投稿されたコメント」「コメント投稿フォーム」を実装する

app/views/books/show.html.erb
:
:
#コメント数
  <td>コメント数:<%= @book.book_comments.count %></td>
:
:
  <table>
    <tbody>
      <% @book.book_comments.each do |book_comment| %>
      <tr>
        <td>
          <%= link_to user_path(book_comment.user) do %>
            <%= image_tag book_comment.user.get_profile_image(100, 100) %></br>
            <%= book_comment.user.name %>
          <% end %>
        </td>
#投稿されたコメント
        <td><%= book_comment.comment %></td>
        <td>
#ログインしているユーザーであれば削除ボタンを表示
          <% if book_comment.user == current_user %>
            <%= link_to "削除する", book_book_comment_path(@book, book_comment), method: :delete %>
          <% end %>
        </td>
      </tr>
      <% end %>
    </tbody>
  </table>
#コメント投稿フォーム
  <div>
    <%= form_with model: [@book, @book_comment] do |f| %>
      <%= f.text_area :comment, rows: '5', placeholder: "コメントをここに", class: "w-100" %>
      <%= f.submit "送信する" %>
    <% end %>
  </div>

ここまでで、コメントの投稿・削除・コメント表示・コメント件数の表示ができるようになりました!

altテキスト

7.バリデーション設定

コメントフォームが空欄の状態でも投稿できてしまうので、バリデーションを設定します!
altテキスト

app/models/book_comment.rb
class BookComment < ApplicationRecord
:
  validates :comment, presence: true, length: { maximum: 200 }
  • 「presence: true」=空欄ではない
  • 「length: { maximum: 200 }」=最大200文字以内

ここまでで、コメント機能の実装が完了となります!
間違っているところ等ありましたらコメントいただけると幸いです🙇

こちらの記事を参考にさせていただきました!!

https://qiita.com/smallisland-ken/items/1e4a2fb13a3d6e8f3b7c

https://qiita.com/kurawo___D/items/d2fefdd329f5310113aa

Discussion