コメント機能の実装

コメント機能の実装

今回は、以前に作成したBookers2というアプリケーションにコメント機能を実装していく。

使用するアプリケーションについて参考URL 作成するアプリケーションについて - takifugu’s blog

コメント機能の作成

コメント機能を実装していく。

手順は下記の流れで作業していく。

  1. コメントのモデルとテーブルの設計と作成。

  2. 関係性(アソシエーション)の記述

  3. コメントのコントローラ作成

  4. ルーティングの記述

  5. コントローラにコメント作成のcreateアクション記述

  6. ビューにコメント投稿欄の作成

  7. コントローラにコメント削除のdestroyアクションの記述

  8. ビューに削除ボタンの実装

コメントのモデルとテーブルの設計と作成

コメント保存用のテーブルには、「コメントの内容」「どの本の投稿にコメントするか。」「誰がコメントしたか。」を定義する必要がある。

このため、comment(コメントの内容)、book_id(どの本へのコメントか)、user_id(コメントした人)のカラムを持たせる必要がある。

カラム名 データ型 カラムの説明
id integer コメントのID
comment text コメントの内容
book_id integer コメントする本のID
user_id integer コメントした人のID

テーブルの設計が完了したので、book_commentモデルを作成する。

$ rails g model BookComment comment:text book_id:integer user_id:integer

データベースへマイグレーションする。

$ rails db:migrate

関係性(アソシエーション)の記述

Userモデル、Bookモデル、BookCommentモデルの関係性をER図で表すと下記のようになる。

UserモデルとBookCommetnモデル、BookモデルとBookCommentモデルの関係性をそれぞれ考えると、下記のようになる。

Userモデル:BookCommentモデル → 1:多

Bookモデル:BookCommentモデル → 1:多

上記を踏まえてモデルに記述をしていく。(アソシエーション部分を抜粋)

app/models/user.rb

  has_many :books, dependent: :destroy
  has_many :book_comments, dependent: :destroy

app/models/book.rb

  belongs_to :user
  has_many :book_comments, dependent: :destroy

app/models/book_comment.rb

  belongs_to :user
  belongs_to :book

これでモデルの準備が完了しました。

コメントのコントローラ作成

book_commentコントローラを作成していきます。

$ rails g controller book_comments

ルーティングの記述

コメント機能は、コメント作成機能とコメント削除機能を実装するため、createアクションとdestroyアクションのルーティングを記述していく。

コメントは投稿した本に対して行われるため、book_commetnsはbooksに結びつき、下記のようにネストする記述を行います。

config/routes.rb(追加部分を抜粋)

  resources :books, only: [:index, :show, :edit, :create, :destroy, :update] do
    resources :book_comments, only: [:create, :destroy]
  end
ルーティングの確認
$ rails routes

コメント投稿機能の実装

book_commentコントローラにコメント作成機能のアクションを記述する。

app/controllers/book_controller.rb

def create
    book = Book.find(params[:book_id])
    comment = current_user.book_comments.new(book_comment_params)
    comment.book_id = book.id
    comment.save
    redirect_to request.referer
  end

private
  def book_comment_params
    params.require(:book_comment).permit(:comment)
  end

※redirect_to request.refererについて

Referer リクエストヘッダーには、現在リクエストされているページへのリンク先を持った直前のウェブページのアドレスが含まれています。

そのため、上記のような記述をすることで、直前のページにredirectすることができます。

bookコントローラのshowアクションに記述の追加

app/controllers/books_controller.rb

  def show
    @book = Book.find(params[:id])
    @book_comment = BookComment.new     #追加
  end

ビューにコメント投稿欄の作成

createアクションを記述したので、book_commentsフォルダに、コメント表示部分をindex.html.erb、コメント作成部分をform.html.erbとして部分テンプレートを作成する。

そして、books/show.html.erbにコメント作成機能、コメントの一覧表示を記述する。

app/views/book_comments/_form.html.erb

<%= form_with(model:[book, book_comment], local: true) do |f| %>
  <%= f.text_area :comment, rows:'5',placeholder: "コメントをここに", class: "w-100" %>
  <%= f.submit "送信" %>
<% end %>

book_commentモデルはbookモデルにネストしているため、

book_commentモデルクラスのインスタンスにデータを保存するときは、form_withにbookとbook_commentの2つの引数を渡す必要がある。

rows: '5'でコメント投稿欄を5行に指定。

class: "w-100"で横幅100%というBootstrapを使用した記述。

app/views/book_comments/_form.html.erb

<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(50,50) %><br>
            <%= book_comment.user.name %>
          <% end %>
        </td>
        <td><%= book_comment.comment %></td>
        <td>
        </td>
      </tr>
      <% end %>
  </tbody>
</table>

app/views/books/show

:
      </table>
      <%= render "book_comments/index", book: @book %>
      <%= render "book_comments/form", book: @book, book_comment: @book_comment %>
:

上記でコメント投稿機能の作成が完了。

コメント削除機能の実装

次にコメント削除機能を実装していく。

destroyアクションの記述

book_commentsコントローラにdestroyアクションを記述していく。

app/controller/book_comments_controller.rb

:
  def destroy
    BookComment.find_by(id: params[:id], book_id: params[:book_id]).destroy
    redirect_to request_referer
  end
:

BookComment.find_by(id: params[:id], book_id: params[:book_id]).destroy

URLから、IDとコメントをした本のIDを取得し、削除するコマンド。

削除ボタンの作成

book_commentsファイルの_index部分テンプレートのテーブルの要素に削除ボタンの追加。

自分が投稿したコメントのみに削除ボタンが表示されるようにする。

app/views/book_comments/_index.html.erb

:
<td>
  <% if book_comment.user == current_user %>
    <%= link_to "Destroy", book_book_comment_path(book, book_comment), method: :delete, class: "btn btn-sm btn-danger", "data-confirm" => "本当に消しますか?" %>
  <% end %>
</td>
:

上記でコメント削除機能の作成が完了。

コメント件数の表示

ユーザーの詳細画面、本の一覧画面、本の詳細画面に登録されている本にコメント数を表示させていく。

本の詳細画面のテーブル要素に下記記述を追加。

app/views/books/show.html.erb

:
<td>
  コメント数:<%= @book.book_comments.count %>
</td>
:

ユーザー詳細画面と本の一覧画面は、booksフォルダの_index部分テンプレートに記述を追加。

部分テンプレートのため、@はつけない。

app/views/books/_index.html.erb

:
<td>
  コメント数:<%= book.book_comments.count %>
</td>
:

上記で、コメント件数の表示が完了。

以上。