【Rails】コメント機能の非同期通信化
コメント機能を非同期通信を用いて実装します。
実装要件
- コメント一覧を部分テンプレートとすること
- サーバーからのレスポンスでコメント一覧のテンプレートを返すこと
- コメントの投稿後、コメントフォームの値に前回の投稿が残らないようにすること
- form_withを使うこと
Viewファイルの作成
部分テンプレートファイルの作成、非同期通信する要素にID属性を追加します。
以下画像のように3枠に分けて作成します。
部分テンプレートファイル作成
①コメント数
コメント数: <%= book.book_comments.count %>
②コメント一覧
<table>
<tbody>
<% book.book_comments.each do |book_comment| %>
<tr>
<td>
<%= link_to user_path(book_comment.user) do %>
<%= image_tag book_comment.user.get_profile_image, size: "50x50" %><br>
<%= book_comment.user.name %>
<% end %>
</td>
<td><%= book_comment.comment %></td>
<td>
<% if book_comment.user == current_user %>
<%= link_to "Destroy", book_book_comment_path(book, book_comment), method: :delete, class: "btn btn-sm btn-danger float-end", remote: true %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
remote: true
は非同期通信を行うためのオプションです。Railsではデフォルトで非同期通信を処理するためのライブラリが組み込まれているため、実装することによりページがリロードされることなく変更を反映することができます。
③コメント投稿フォーム
<%= form_with model: [book, book_comment], local: false do |f| %>
<%= f.text_area :comment, rows:'5', placeholder: "コメントをここに", class: "w-100", id: "comment_textarea" %>
<%= f.submit "送信" %>
<% end %>
form_with
ヘルパーではlocal: false
を指定することで、非同期通信を行うことができます。
id: "comment_textarea"
を追加して、comment_textarea
というIDがテキストエリアに割り当てられるようにします。
idを追加
showページ
<div class="container">
<div class="row">
<div class="col-md-3">
<h2>User info</h2>
<%= render "users/info", user: @user %>
<h2 class="mt-3">New book</h2>
<%= render "form", book: @books %>
</div>
<div class='col-md-8 offset-md-1'>
<h2>Book detail</h2>
<table class="table">
<tr>
<td><%= link_to @book.user do %>
<%= image_tag @book.user.get_profile_image, size:"50x50" %><br>
<%= @book.user.name %>
<% end %>
</td>
<td><%= link_to @book.title, @book %></td>
<td><%= @book.body %></td>
<td id="favorite_btn_<%= @book.id %>">
<%= render "favorites/btn", book: @book %>
</td>
+ <td id="comment_counter">
+ <%= render "book_comments/counter", book: @book %>
+ </td>
<% if @book.user == current_user %>
<td><%= link_to "Edit", edit_book_path(@book), class: "btn btn-sm btn-success" %></td>
<td><%= link_to "Destroy", @book, method: :delete, data: { confirm: "本当に消しますか?" }, class: "btn btn-sm btn-danger" %></td>
<% end %>
</tr>
</table>
+ <div id="comment_index">
+ <%= render "book_comments/index", book: @book %>
+ </div>
<%= render "book_comments/form", book: @book, book_comment: @book_comment %>
</div>
</div>
</div>
IDを要素に追加することで、その要素を独自に特定することができます。JavaScriptのコードでは、IDを使って特定の要素にアクセスして操作することができます。
Controller編集
htmlではなく、jsファイルを読み込ませるため、コントローラを以下の通り編集します。
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 request.referer
end
def destroy
BookComment.find(params[:id]).destroy
- redirect_to request.referer
end
private
def book_comment_params
params.require(:book_comment).permit(:comment)
end
end
解説:
redirect_to
を削除します。非同期通信を行う場合は、JavaScriptファイル(.js.erb)を使用してビューを更新します。アクション内にrender
やredirect_to
の記述がない場合、Railsは自動的に対応するJavaScriptファイルを探しに行きます。例えば、create.js.erbという名前のファイルがあれば、それが読み込まれます。
js.erbファイル作成
js.erbファイルを作成します。
$('#comment_counter').html("<%= j(render 'book_comments/counter', book: @comment.book) %>");
$('#comment_index').html("<%= j(render 'book_comments/index', book: @comment.book) %>");
$('#comment_counter').html("<%= j(render 'book_comments/counter', book: @comment.book) %>");
$('#comment_index').html("<%= j(render 'book_comments/index', book: @comment.book) %>");
$('#comment_textarea').val("");
解説:
$('#comment_textarea').val("");
は、コメントフォームのテキストエリアの値を空にするためのコードです。
テキストエリアはユーザーがテキストを入力するためのものであり、その入力されたテキストは「値(value)」として表現されます。.val("")
は、指定された要素の値を設定するための関数であり、カッコ内には新しい値を指定します。
この場合、コメントフォームのテキストエリアを対象にしています。$('#comment_textarea')
は、IDがcomment_textarea
である要素を選択するためのセレクタです。.val("")
とすることで、テキストエリアの値が空文字列に設定され、すなわちテキストエリアが空になるという動作を意味します。
つまり、このコードを実行することで、コメントの入力欄が空にリセットされ、ユーザーは新しいコメントを入力するために空のフォームから始めることができます。
コメント機能の非同期通信化でした☆
Discussion