はじめに
ブログっぽいWebサービスにコメント機能を追加してみました。
自分のメモ用、そして同じような機能を実装しようとしている初学者の方の参考になれば幸いです!
前提
Ruby : 2.6.4
Rails : 5.2.3
ユーザー認証にdeviseを使用しています。
#Comment Model作成
UserモデルのユーザーがPostモデルに対してコメントをできるようにします。
実装方法としては、フォロー機能のように中間テーブルを用意し、その中間テーブル(Comment Model)のcontentカラムに
実際のコメントを追加します。
$ rails g model comment content:string user:references post:references
$ rails db:migrate
has_many :comments
has_many :comments
class Comment < ApplicationRecord
belongs_to :user
belongs_to :post
end
comment.rbについてですが、自分の手動でのミスにより、post_idとの関連付けがうまくいっていない状態で
コメントのテストを行なってしまい、外部キーがnilになってしまいエラーになってしまいました。
この問題の解決は、
class Comment < ApplicationRecord
belongs_to :user
belongs_to :post, optional: true
end
このように、optional: true を追記することで(一時的に)解決できます。
ここで、自動テストのありがたみに気づきました(笑)
外部キーのnilを許可するパターンはあまりない気がするので、使うことはそこまでないのかなと思います。
コントローラー作成
comments_controller.rbを作成
$ rails g controller comments
class CommentsController < ApplicationController
before_action :authenticate_user!
def create
post = Post.find(params[:post_id])
@comment = post.comments.build(comment_params)
@comment.user_id = current_user.id
if @comment.save
flash[:success] = "コメントしました"
redirect_back(fallback_location: root_path)
else
flash[:success] = "コメントできませんでした"
redirect_back(fallback_location: root_path)
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
createアクションについて。
@comment.user_id = current_user.idを書いている理由として、
上の2行だけではコメントをしたユーザーの関連付けをできないため書いています。
ルーティング
resources :posts do
resources :comments, only: [:create]
end
Views
自分の場合はPostのshow.html.erbにコメント一覧とフォームを追加したかった為ここに追加します。
<div class="comment-wrapper border-top mb-10">
<p class="mt-5">コメント一覧</p>
<% @comments.each do |c| %>
<div>
<% unless c.user.blank? %>
<a href="<%= user_path(c.user_id) %>"><%= image_tag c.user.image.to_s,
class:"rounded-circle icon_image mr-3 mb-3"%></a>
<% end %>
<%= c.user.username unless c.user.blank? %>
<br />
<%= c.content %>
</div>
<br />
<% end %>
<% if user_signed_in? %>
<%= form_with(model: [@post, @comment], local: true) do |f| %>
<%= f.text_area :content, class: "form-control", rows: 5 %>
<%= button_tag type: "submit", class: "btn btn-success float-right mt-1" do %>
<i class="far fa-comments"></i> コメントする
<% end %>
<% end %>
<% end %>
</div>
特に難しいことはしていませんが、form_with(model: [@post, @comment], local: true) do |f|は、
commentがpostに紐づいている為配列にします。
def show
@post = Post.find(params[:id])
@comments = @post.comments
@comment = @post.comments.build
end
show.html.erb内で使用している@commentと@commentsは上記のようになります。
完成
ログインしていない時
ログイン時
終わりに
コメント削除機能をつけ忘れていたので実装します。
何か間違っている点などありましたらコメントやツイッターでお願いします!