コメント投稿、削除、編集機能のajax化
コメント投稿、削除処理のajax
form_withのlocal: trueを削除して非同期処理にする。
app/views/comments/_form.html.erb
<div class="row mb-3"> <div class="col-lg-8 offset-lg-2"> <%= form_with model: comment, url: [board, comment], id: 'new_comment' do |f| %> <%= f.label :body %> <%= f.text_area :body, class: 'form-control mb-3', id: 'js-new-comment-body', row: 4, placeholder: Comment.human_attribute_name(:body) %> <%= f.submit t('defaults.post'), class: 'btn btn-primary' %> <% end %> </div> </div>
コメントの削除ボタンlink_toにremote: trueを追加 app/views/comments/_comment.html.erb
<%= link_to comment_path(comment), class: 'js-delete-comment-button', method: :delete, data: { confirm: t('defaults.message.delete_confirm') }, remote: true do %> <%= icon 'fa', 'trash' %> <% end %>
コメント作成、削除時の動的レンダリング処理を追加
コメントの追加に成功した場合、追加したコメントをコメント一覧に追加する処理をjavascriptで実装する。
また、コメントの追加に失敗した場合は、エラーメッセージを表示するようにする。
app/views/comments/create.js.erb
$("#error_messages").remove() <% if @comment.errors.present? %> $("#new_comment").prepend("<%= j(render('shared/error_messages', object: @comment)) %>") <% else %> $("#js-table-comment").prepend("<%= j(render('comments/comment', comment: @comment)) %>") $("#js-new-comment-body").val('') <% end %>
コメントの追加と同様に、コメントの削除した時にコメントリストから対象のコメントを取り除く。
app/views/comments/destroy.js.erb
$("tr#comment-<%= @comment.id %>").remove()
コメント編集ajax化
app/assets/javascripts/edit_comment.js
$(function() { $(document).on("click", '.js-edit-comment-button', function(e) { e.preventDefault(); const commentId = $(this).data("comment-id") switchToEdit(commentId) }) $(document).on("click", '.js-button-edit-comment-cancel', function() { clearErrorMessages() const commentId = $(this).data("comment-id") switchToLabel(commentId) }) $(document).on("click", '.js-button-comment-update', function() { clearErrorMessages() const commentId = $(this).data("comment-id") submitComment($("#js-textarea-comment-" + commentId).val(), commentId) .then(result => { $("#js-comment-" + result.comment.id).html(result.comment.body.replace(/\r?\n/g, '<br>')) switchToLabel(result.comment.id) }) .catch(result => { const commentId = result.responseJSON.comment.id const messages = result.responseJSON.errors.messages showErrorMessages(commentId, messages) }) }) function switchToLabel(commentId) { $("#js-textarea-comment-box-" + commentId).hide() $("#js-comment-" + commentId).show() } function switchToEdit(commentId) { $("#js-comment-" + commentId).hide() $("#js-textarea-comment-box-" + commentId).show() } function showErrorMessages(commentId, messages) { $('<p class="error_messages text-danger">' + messages.join('<br>') + '</p>').insertBefore($("#js-textarea-comment-" + commentId)) } function submitComment(body, commentId) { return new Promise(function(resolve, reject) { $.ajax({ type: 'PATCH', url: '/comments/' + commentId, data: { comment: { body: body } } }).done(function (result) { resolve(result) }).fail(function (result) { reject(result) }); }) } function clearErrorMessages() { $("p.error_messages").remove() } });
コメントコントローラを修正
コメント作成時のredirect_backを削除し、コメント削除処理を追加
app/controllers/comments_controller.rb
class CommentsController < ApplicationController def create @comment = current_user.comments.build(comment_params) @comment.save end def destroy @comment = current_user.comments.find(params[:id]) @comment.destroy! end
コメント削除のルートを追加 config/routes.rb
Rails.application.routes.draw do resources :boards do resources :comments, only: %i[create destroy], shallow: true collection do get :bookmarks end end end
参考文献