オリジナルの写真と投稿アプリを作成した時にコメント機能に後からAjaxで実装してみようと思ったらかなり手こずったので忘れない為に備忘録を残します。
投稿した写真にログインしたユーザーがコメント出来る機能になってます。
コントローラーの編集
投稿した写真の詳細ページにコメントしたいのでアクションはcreateとdestroyの二つ
画面遷移はしたくないのでrenderやredirectの記述はしない
@comment = Comment.find(params[:id])をdestriyメソッドの下に書くと意味がないので一番上に記述する
def create
@post = Post.find(params[:post_id])
@comment = Comment.new(comment_params)
@comment.save
end
def destroy
@comment = Comment.find(params[:id])
@post = Post.find(params[:post_id])
@post_comments = @post.comments
Comment.find_by(id: params[:id], post_id: params[:post_id]).destroy
end
private
def comment_params
params.require(:comment).permit(:text).merge(user_id: current_user.id, post_id: params[:post_id])
end
フォームの編集と部分テンプレートの追記
form_withのlocalオプションをfalseにする
投稿したコメントを表示するための部分テンプレートを挿入
<%= form_with model: [@post, @comment], local: false do |f|%>
<div class="post-field">
<%= f.label :text, "コメント" %>
<%= f.text_area :text, class: :post_text_field %>
</div>
<div class="show__comment__actions">
<%= f.submit "コメントを投稿する", class: :comment_form__btn %>
</div>
<% end %>
<ul class="show_comments_lists">
<%= render "comments/comments", post: @post, comments: @comments %>
</ul>
投稿したコメントを表示するための部分テンプレートを作成
link_toにはremote: trueを追記する
<% post.comments.each do |comment| %>
<li id="comment_<% @comment.id %>" class="show_comments_list">
<%= comment.text %><br>
by@<%= comment.user.name %>
<% if user_signed_in? && current_user.id == comment.user_id %>
<%= link_to "コメントを削除する", post_comment_path(comment.post, comment), method: :delete, remote: true, class: :post_delete_btn %>
<% end %>
</li>
<% end %>
*ここで注意なのがidの指定に<% @comment.id %>を記述すること。削除機能を実装する際に重要になる。
下準備が終了したのでAjaxでの投稿機能と削除機能を書いていく
コメントを投稿するためのJavaScriptファイルを作成
$("textarea").val('');
$('.show_comments_lists').html("<%= j(render 'comments/comments', post: @post, comment: @comment) %>");
*コメントが投稿された後にフォームを空にしたいのでtextareaのvalue属性をval('');と記述
コメントを表示するためにhtml()を記述してrenderで指定した部分テンプレートに更新させる。(jはescape_javascriptの略)
コメントを削除するためのJavaScriptファイルを作成
$('#comment_<%= @comment.id %>').remove();
$('.show_comments_lists').html("<%= j(render 'comments/comments', post: @post, comment: @comment) %>");
ここが一番手間取った…
remove()にshow_comments_listsを指定するとコメントが全て削除されるのでcomment_<%= @comment.id %>を指定。
@comment.idはコントローラーにdestroyアクションに@comment = Comment.find(params[:id])を記述しているから使える(まずこれを書いていなかったのでエラーが発生しまくった)
あと勘違いしていたのがremove()。てっきり削除した上で画面の表示を変えてくれるのかと思ってたら削除しかしないメソッドだった。
なのでcreate.js.erbと同様にrenderで指定した部分テンプレートに更新させるための記述を追記 。
以上でAjax化終了
参考になる記事があった上で実装にかなり手間取ったのでコントローラーでの変数の指定する際の意味やメソッドの特性をもっと知るべきだなと感じました。
参考にさせて頂いた記事はこちらです。
https://qiita.com/coneco12_/items/61174a80a611b7e0049e