初めに
プログラミング学習中です。もし、間違ってるところがあれば申し訳ありません
復習とわからないところの炙り出しです。
本の投稿サイトにコメント機能をつけていきます。
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 なので、
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
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ページ
<!--コメントの数-->
<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>
部分テンプレートで飛ばしています。
<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>
コントローラーの記述
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>
コメント機能を作成する
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)
と記載がありますが、下記と同じ意味になります。(うう。。)
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持ってきてるってことでしょうか。
終わりです。