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

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


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

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

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

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

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

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

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

```
rails g model BookComment comment:text user_id:integer book_id:integer
```
rails db:migrateしてデータベースに反映してください。

<h2>アソシエーションを記述</h2>
user:book_comment = 1:N
book:book_comment = 1:N なので、


```perl: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
```

```perl:book_comment.rb 
class BookComment < ApplicationRecord
  belongs_to:user
  belongs_to:book
  validates :comment, presence: true,length:{maximum:140}
  #バリデーションも追記してあります。長さ最大１４０字、空欄はNG!
end
```
ポイント
＊１：NのNの方のモデルファイルには、has many 1の方にはbelongs_toを書く。
＊dependent:destroyは1:Nにおいて1が消された場合、それに関連(dependent)してるものもdestroyするよというような意味だったと思います。userが消されたらそのuserが投稿した内容も一緒に消えてくれます。

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

```
rails g controller PostComments　create destroy
```
ここで復習：modelファイルは単数系、コントローラーは複数系

<h2>ルーティングの設定</h2>

```
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のルーティングが入っています。
親子関係とか、ネストする　というそうです。
ネストしなかったらまずいというわけではないですが、ルーティングがわかりやすいそうです。

<h2>viewページ　</h2>

```perl: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>
```
部分テンプレートで飛ばしています。


```perl:_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>
```

<h2>コントローラーの記述</h2>

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

<h2>indexページでのコメント件数の表示</h2>

```
<tbody>
<tr>
 <% @books.each do |book| %>
 
#間は省略。

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

</tbody>
```
<h2>コメント機能を作成する</h2>

```perl: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```

<details><summary>↓投稿機能の復習</summary><div>

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

</div></details>

<h2>destroyアクション</h2>

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


```
  def destroy
    BookComment.find_by(id: params[:id], book_id: params[:book_id]).destroy
    redirect_to book_path(params[:book_id])
  end
```
<details><summary>find_byって何だっけ。。。？</summary><div>
一言で言うと、「主キー(id)以外のカラムを指定しても、見つかった1レコードを返せる」だそう。
book_commentモデルは、自身の主キーであるidと、外部キーとしてbook_idを持ってるわけで、
両方消すから、両方のid持ってきてるってことでしょうか。

</div></details>

終わりです。