コメント機能の作成について

どうもどハマりエンジニアです。

 

ここからリレーションなども絡んできてかなり初学者(自分)には難しく感じるとろこになりました。ですが気合を入れて頑張っていきましょう!

 

 ではまず最初にイメージ図(ER図)を簡単に手書きでパパッと書いておくとイメージが湧きやすいのではないかと思います。簡単なところは省いていきます!

 

①コメントのモデル作成(Comment)

 

②コメントコントローラの作成(Comments)

 

③各モデルにアソシエーションを追加

<user.rb>

has_many :comments, dependent: :destroy

<board.rb>

has_many :comments, dependent: :destroy

<comment>

belongs_to :board
belongs_to :user

 

④commetのマイグレーションの設定

class CreateComments < ActiveRecord::Migration[5.2]
def change
create_table :comments do |t|
t.text :body, null: false
t.references :board, foreign_key: true
t.references :user, foreign_key: true

t.timestamps
end
end
end

 

⑤ルーティングの設定

resources :boards, only: %i[index new create show] do
resources :comments, only: %i[create], shallow: true
end

shallow: true このオプションを使うことで、浅いネストを作ることができる。

例えば、boards/board_id/comments/comments_id といいたように最後のコメントのidは不要なのでこれを省いて作成してくれる。

 

⑤boards_controller

def show
@board = Board.find(params[:id])
@comment = Comment.new
@comments = @board.comments.includes(:user).order(created_at: :desc)
end

ボードのテンプレートの下記にコメント欄を作りたいので、インスタンスを作成し、

@commentsでコメントの情報とuserの情報を取得する。SQLへの問い合わせが減る。

 

⑥boards/show.html.erbにてrenderでテンプレートをもってくる

<boards/show.html.erb>

<!-- コメントフォーム -->
<%= render 'comments/form', board: @board, comment: @comment %>
<!-- コメントエリア -->
<%= render 'comments/comments', comments: @comments %>

<_form.html.erb>

<%= form_with model: comment, url: [board, comment], local: true do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :body%>
<%= f.text_area :body, class: 'form-control mb-3' %>
<%= f.submit '投稿', class: 'btn btn-primary' %>
<% end %>

urlの送り先が大事!!深く理解出来てないのですが、boardとcomment両方に情報が必要なため。

 

 

ここから難しかった・・・

<boards/show.html.erb>

 
<!-- コメントエリア -->
<%= render 'comments/comments', comments: @comments %>

今回はshowのテンプレートにコメントを入れたい。コメントのパーシャルはcomments/の中にある。そこでまずはいつも通りの書き方で上記のようにかく。

 

<_comments.html.erb>

<div class="row">
<div class="col-lg-8 offset-lg-2">
<table id="js-table-comment" class="table">
<%= render comments %>
</table>
</div>
</div>

 boardとcommentの関係でパーシャルを二段階ふむ必要があるのではないかと考えた。。。 多分・・・

 render comments の複数形でcommentパーシャルをコメントの件数分eachして表示させている。これは、renderでオブジェクトの集合(コレクション)を指定する記法の省略形。

<%= render partial: "comment", collection: @comments %>

# 省略形
<%= render @comments %>

講師に聞いたところ「

上記のコレクションをrenderすると、render先のパーシャルでコレクションを単数系にしたローカル変数が利用できる様になります。

本来であれば自分でeach文を作ってループ変数やローカル変数を定義するといった必要がある部分を、Railsの記法に従うことで省略して利用できる形になります。

こういった一見ブラックボックスとなる挙動は最初は分かりづらいですが、「設定より規約」というRailsの設計思想に従って「規約」として覚えてしまうことで、コードの記述量が減るので実装の効率が良くなります。

Railsの規約を前提とした実装は現場でも良く出てくるので、1つずつ覚えて使いこなしていきましょう。」

とのこと。なるほど、規約として覚えればいいのか。

<_comment.html.erb>

<h3 class="small"><%= comment.user.decorate.full_name %></h3>
<div id="js-comment-<%= comment.id %>">
<p><%= simple_format(comment.body) %></p>

こんな感じでcommentが使えるようになった!

 

⑦comments_controllerにてcreateしていく!

<comments_controller.rb>

class CommentsController < ApplicationController
def create
comment = current_user.comments.build(comment_params)
if comment.save
redirect_to board_path(comment.board), success: 'コメントを作成しました'
else
flash[:danger] = 'コメントを作成できませんでした'
redirect_to board_path(comment.board)
end
end

private

def comment_params
params.require(:comment).permit(:body).merge(board_id: params[:board_id])
end
end

 

上記の手順で一応保存する作業まで完了!

 

なかなか難しいぞ・・・

だが頑張るしかない!