Railsコメント機能の非同期通信化(Ajax)
前回の記事の続き
開発環境
ruby 3.1.2p20
Rails 6.1.7.4
Cloud9
前提
・Userモデル、Bookモデル、BookCommentモデルは作成済み
・Devise導入済み
step1 jQueryの導入
まずはjQueryを読み込みます。
$ yarn add jquery
上記コマンドを実施します。
次に、config/webpack/environment.js に以下のコードを記述します。
const { environment } = require('@rails/webpacker')
// 追加ここから
const webpack = require('webpack')
environment.plugins.prepend('Provide',
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery'
})
)
// 追加ここまで
module.exports = environment
最後に、app/javascript/packs/application.js に以下を追記します。
require("jquery") //このコードを追加
これで準備が整いました。
step2 コメント部分のテンプレート化
今回テンプレート化が必要な部分(非同期通信で更新したい部分)は
・コメント一覧表示(book_comments/_index.html.erb)
・コメント送信フォーム(book_comments/_form.html.erb)
・コメント数表示(book_comments/_counter.html.erb)
の3か所です。
<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: "100x100" %><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, remote: true, data: {"turbolinks" => false}, class: "btn btn-danger pull-right" %> #ココ
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
コメント削除機能の Destroyボタンに、
remote: true, data: {"turbolinks" => false}
を追記します。
<%= form_with model:[book, book_comment], local: false do |f| %> #ココ
<%= f.text_area :comment, rows:'5',placeholder: "コメントをここに", class: "w-100 comment-textarea" %> #ココ
<%= f.submit "送信する", class: "btn btn-lg btn-base-1 mt-20 pull-right btn-secondary" %>
<% end %>
※form_with 部分に local:false を追記します。
なぜかは全くわからないのですが、form_with側にはremote: true, data: {"turbolinks" => false}
と記述しても、非同期通信されません。必ずlocal:false
を記述する必要があります。
誰か、理由がわかったら教えてください...😂
また、f.text_area 部分に comment-textarea クラスを追記します。
このクラスは後にjsファイル内で使用します。
コメント数: <%= book.book_comments.count %>
step3 テンプレート読み込み
次に、step2 で作成したテンプレートを読み込みます。
読み込み部分に idを付与するのを忘れないようにします。
この idは後にjsファイルで使用します。
<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:"100x100" %><br>
<%= @book.user.name %>
<% end %>
</td>
<td><%= link_to @book.title, @book %></td>
<td><%= @book.body %></td>
<td id="book-comments-counter"> #ココ
<%= render 'book_comments/counter', book: @book %> #ココ
</td>
<td id="favorite_buttons_<%= @book.id %>">
<%= render "favorites/btn", book: @book %>
</td>
<% if @book.user == current_user %>
<td><%= link_to 'Edit', edit_book_path(@book), class: "btn btn-sm btn-success edit_book_#{@book.id}" %></td>
<td><%= link_to 'Destroy', @book, method: :delete, data: { confirm: '本当に消しますか?' }, class: "btn btn-sm btn-danger destroy_book_#{@book.id}"%></td>
<% end %>
</tr>
</table>
<div id="book-comments-index"> #ココ
<%= render "book_comments/index", book: @book %> #ココ
</div>
<%= render "book_comments/form", book: @book, book_comment: @book_comment %> #ココ
</div>
編集したのは、#ココ と書いてある3か所です。
step4 コントローラの編集
次に、book_comments_controller を編集します。
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
@comment = BookComment.find_by(id: params[:id], book_id: params[:book_id])
@comment.destroy
# redirect_to request.referer
end
リダイレクトを削除しました。
このおかげで、create / destroyの処理後、jsファイルを参照してくれます。
また、commentを @commentに変更しました。
後にjsファイルで使用するためです。
step5 jsファイルの作成
create.js.rb
destroy.js.rb を作成します。
$('#book-comments-counter').html("<%= j( render 'book_comments/counter', book: @comment.book ) %>")
$('#book-comments-index').html("<%= j(render "book_comments/index", book: @comment.book
$('.comment-textarea').val("");
$('#book-comments-counter').html("<%= j(render 'book_comments/counter', book: @comment.book) %>")
$('#book-comments-index').html("<%= j(render 'book_comments/index', book: @comment.book) %>")
参照
Discussion