Ryota400’s blog

エンジニアを目指して書いてます。

コメント投稿、削除、編集機能の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

参考文献

qiita.com

yoshi14m3185.hatenablog.com