1
1

More than 3 years have passed since last update.

[Ruby on rails]コメント機能をつける

Last updated at Posted at 2021-07-05

初めに

プログラミング学習中です。もし、間違ってるところがあれば申し訳ありません
復習とわからないところの炙り出しです。

本の投稿サイトにコメント機能をつけていきます。

Qコメントの投稿テーブルにはまず何が必要なのか考えてみてください。(必要なカラム、データ型)
1,コメント毎のIDである[id](integer型) ※integerは整数

2,コメント本文である[comment](text型)

3,誰がコメントしたか[user_id](integer型)

4,どの投稿に対してコメントされてるか[book_id](integer型)
以上4つです。

コメント保存用のモデルを作成する

ターミナルに以下の通り記載します。

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

rails db:migrateしてデータベースに反映してください。

アソシエーションを記述

user:book_comment = 1:N
book:book_comment = 1:N なので、

book.rb
class Book < ApplicationRecord

belongs_to:user
validates :title, presence: true
validates :body, presence: true,length:{maximum:200}
has_many :book_comments, dependent: :destroy #ここを追記しました
end

同様に、user.rbにも以下追記。

has_many :book_comments, dependent: :destroy
book_comment.rb
class BookComment < ApplicationRecord
  belongs_to:user
  belongs_to:book
  validates :comment, presence: true,length:{maximum:140}
  #バリデーションも追記してあります。長さ最大140字、空欄はNG!
end

ポイント
*1:NのNの方のモデルファイルには、has many 1の方にはbelongs_toを書く。
*dependent:destroyは1:Nにおいて1が消された場合、それに関連(dependent)してるものもdestroyするよというような意味だったと思います。userが消されたらそのuserが投稿した内容も一緒に消えてくれます。

コントローラーの作成

Qコメントコントローラーに必要なアクションは?
投稿する createアクション、投稿消すdestroyアクション。
コメント詳細ページ、一覧ページは作成しません。

rails g controller PostComments create destroy

ここで復習:modelファイルは単数系、コントローラーは複数系

ルーティングの設定

Rails.application.routes.draw do

  devise_for :users
  root to:'homes#top'
  resources:books,only:[:new,:create,:index,:show,:destroy,:edit,:update]  do
    resources:book_comments,only:[:create,:destroy]
  end

booksのルーティングの中に、book_commentsのルーティングが入っています。
親子関係とか、ネストする というそうです。
ネストしなかったらまずいというわけではないですが、ルーティングがわかりやすいそうです。

viewページ 

books/show.html.erb
 <!--コメントの数-->
  <td>コメント数:<%= @books.book_comments.count %></td>
   <% if @books.user == current_user %>
  <td class="botton"><%= link_to"Edit",edit_book_path(@books),class:'btn btn-success'%></td>
  <td class="botton"><%= link_to"Destroy",book_path(@books), method: :delete,class:'btn btn-danger'%></td>
  <% end %>
  </tr>
  </tbody>
  </table>
 <div id="comments-area"><%= render "book_comments/comment",books: @books,book_comment: @book_comment %></div>

部分テンプレートで飛ばしています。

_comment.html.erb
<table><% books.book_comments.each do |book_comment| %>

   <tr>
    <td>
    <%= attachment_image_tag book_comment.user, :profile_image, format: 'jpeg',size: "50x50",fallback: "no_image.jpg" %><br>
    <%=link_to user_path(books.user.id) do %><%= book_comment.user.name %><% end %></td>


    <td><%= book_comment.comment %></td>
  <% if book_comment.user == current_user %> #コメント削除のところ。
    <td><%= link_to "Destroy", book_book_comment_path(book_comment.book, book_comment), method: :delete,remote: true,class:"btn btn-danger" %></td>

  <% end %>
  </tr>
  <% end %>

 </table>

 <div class="form-group">
  <label for="newcomment">Comment</label>



 <%= form_with(model:[books, book_comment], local: true) do |f| %>
  <%= f.text_area :comment, rows:'5',placeholder: "コメントをここに",class:"form-control" %>
  <%= f.submit "送信する" %>
 <% end %>
 </div>

コントローラーの記述

books_contriller.rb
  def show
    @books=Book.find(params[:id])
    @book=Book.new
    @book_comment = BookComment.new
  end

indexページでのコメント件数の表示

<tbody>
<tr>
 <% @books.each do |book| %>

#間は省略。

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

</tbody>

コメント機能を作成する

books_controller.rb
class BookCommentsController < ApplicationController

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 book_path(book)

end

 def destroy
 end

  private

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

createアクションに、
comment = current_user.book_comments.new(book_comment_params)
と記載がありますが、下記と同じ意味になります。(うう。。:cold_sweat:
comment = BookComment.new(post_comment_params)
comment.user_id = current_user.id

↓投稿機能の復習

1行目:book = Book.find(params[:book_id]) 
(params[:book_id]) で、本の投稿から”ある投稿”を取り出せます。
findメソッドを利用して、データベース から取り出して、bookというローカル変数に入れてあります。
2行目 :コメントを新規投稿するための空のインスタンスを作っています。
3行目:comment.book_id=book.id  空のインスタンスのbook_idは、今取り出してる"ある投稿”のidだよという意味だと思います。”ある投稿”に対してコメントしますよ〜という感じ

destroyアクション

もう、上でdestroyのviewページは記載済みです。

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

find_byって何だっけ。。。?

一言で言うと、「主キー(id)以外のカラムを指定しても、見つかった1レコードを返せる」だそう。
book_commentモデルは、自身の主キーであるidと、外部キーとしてbook_idを持ってるわけで、
両方消すから、両方のid持ってきてるってことでしょうか。

終わりです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1