kurashiki777 / card_list_share_app

0 stars 0 forks source link

カード詳細ページのコメント欄を非同期化 #42

Open kurashiki777 opened 7 months ago

kurashiki777 commented 7 months ago

カードの譲渡などの話しをする際に毎回リロードするのはユーザー体験としては良くないかと思うので非同期化

kurashiki777 commented 4 months ago

使用しているPC mac

やりたいこと actiion cableで編集のリアルタイム更新

現状発生している問題・エラーメッセージ コメントの編集ボタンを押すとhttp://localhost:3000/~~/edit.turbo_streamのURLに遷移して、コードがそのまま表示されます

どの処理までうまく動いているのか 該当のソースコード

  1. サーバーサイドの設定 CommentChannelを作成して、コメントの更新をリアルタイムで配信する設定をしました

app/channels/comment_channel.rb

class CommentChannel < ApplicationCable::Channel
  def subscribed
    stream_for card
  end

  def unsubscribed
    stop_all_streams
  end

  private

  def card
    Card.find(params[:card_id])
  end
end
  1. CommentsControllerの設定 コメントの作成、編集、更新、削除機能を実装します。コメントが更新された際には、Action Cableを使用してリアルタイムで更新情報を配信します。

app/controllers/comments_controller.rb

class CommentsController < ApplicationController
  before_action :require_login, only: [:create, :edit, :update, :destroy]
  before_action :set_comment, only: [:edit, :update, :destroy]

  def create
    @comment = current_user.comments.build(comment_params)
    @comment.card_id = params[:card_id]
    if @comment.save
      CommentChannel.broadcast_to(@comment.card, render_to_string(partial: 'comments/comment', locals: { comment: @comment }))
    else
      redirect_to card_path(@comment.card), danger: t('defaults.message.not_created', item: Comment.model_name.human)
    end
  end

  def edit
    respond_to do |format|
      format.turbo_stream { render 'edit' }
      format.html { render partial: 'comments/edit_form', locals: { comment: @comment } }
    end
  end

  def update
    if @comment.update(comment_params)
      CommentChannel.broadcast_to(
        @comment.card, 
        { html: render_to_string(partial: 'comments/comment', locals: { comment: @comment }), action: 'update', comment_id: @comment.id }
      )
      head :ok
    else
      render json: { status: 'error', message: @comment.errors.full_messages.join(", ") }, status: :unprocessable_entity
    end
  end

  def destroy
    card = @comment.card
    comment_id = @comment.id
    @comment.destroy
    CommentChannel.broadcast_to(card, { action: 'destroy', comment_id: comment_id })
    head :ok
  end

  private

  def comment_params
    params.require(:comment).permit(:body).merge(card_id: params[:card_id])
  end

  def set_comment
    @comment = Comment.find(params[:id])
  end
end

3.コメント編集フォームとTurbo Streamの設定をしました

app/views/comments/edit.turbo_stream.erb

<turbo-stream target="edit-comment-form-<%= @comment.id %>" action="replace">
  <template>
    <%= render partial: 'comments/edit_form', locals: { comment: @comment } %>
  </template>
</turbo-stream>

app/views/comments/_edit_form.html.erb

<%= form_with model: [comment.card, comment], remote: true, html: { id: "edit-comment-form-#{comment.id}" } do |form| %>
  <div class="field">
    <%= form.text_area :body, rows: 3 %>
  </div>
  <div class="actions">
    <%= form.submit "更新", class: "btn btn-primary" %>
  </div>
<% end %>
  1. コメント表示部分の設定 コメントの表示部分で、編集リンクとTurbo Frameの設定を行います。

app/views/comments/_comment.html.erb

<tr id="comment-<%= comment.id %>" class="bg-white">
  <td class="p-3">
    <%= image_tag comment.user.avatar_url, width: '50', height: '50' %>
  </td>
  <td class="p-3" style="vertical-align: top;">
    <h3 class="text-sm font-semibold"><%= comment.user.decorate.full_name %></h3>
    <div class="text-gray-700">
      <%= simple_format(comment.body) %>
    </div>
    <% if current_user&.own?(comment) %>
      <div class="comment-buttons">
        <table>
          <tr>
            <td>
              <%= link_to "編集", edit_card_comment_path(comment.card, comment, format: :turbo_stream), remote: true, class: "block p-2.5 bg-green-500 text-white text-center rounded hover:bg-green-700", data: { turbo_frame: "edit-comment-form-#{comment.id}" } %>
            </td>
            <td>
              <%= button_to '削除', card_comment_path(comment.card, comment), method: :delete, data: { confirm: '本当に削除しますか?' }, class: "block p-2.5 bg-red-500 text-white text-center rounded hover:bg-red-700" %>
            </td>
          </tr>
        </table>
      </div>
      <%= turbo_frame_tag "edit-comment-form-#{comment.id}" %>
    <% end %>
  </td>
</tr>
  1. JavaScriptの設定 JavaScriptでTurboの設定を行い、Turbo Frameの読み込みイベントを確認します。

app/javascript/packs/application.js

import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

// Tailwind CSS
import "stylesheets/application"
import { Turbo } from "@hotwired/turbo-rails"

Turbo.session.drive = true
Rails.start()
Turbolinks.start()
ActiveStorage.start()

document.addEventListener("turbo:frame-load", () => {
  console.log("Turbo Frame Loaded");
});
  1. Action Cableの設定 Action Cableを使用して、コメントの更新をリアルタイムで反映します。

app/javascript/channels/comment_channel.js

import { createConsumer } from "@rails/actioncable"

const consumer = createConsumer()

document.addEventListener('turbo:load', () => {
  const commentsElement = document.getElementById('comments')
  if (commentsElement) {
    const cardId = commentsElement.dataset.cardId

    consumer.subscriptions.create({ channel: "CommentChannel", card_id: cardId }, {
      received(data) {
        if (data.action === 'update') {
          const commentElement = document.getElementById(`comment-${data.comment_id}`)
          commentElement.outerHTML = data.html
        } else if (data.action === 'destroy') {
          const commentElement = document.getElementById(`comment-${data.comment_id}`)
          commentElement.remove()
        } else {
          commentsElement.insertAdjacentHTML('beforeend', data.html)
        }
      }
    })
  }
})

エラーから考えられる 原因Turboの設定が不十分、またはJavaScriptエラーが発生している可能性がある。

試したこと Turboが正しくインストールされていることを確認するために yarn add @hotwired/turbo-rails を打ちました インストールされてました

コンソールログを見るために app/javascript/packs/application.js document.addEventListener("turbo:frame-load", () => { console.log("Turbo Frame Loaded");

これ追加したのですがコンソールログが見れなかった

参考にしたURL・使用したプロンプト https://qiita.com/mitaninjin/items/5a58533a183e62307a6c 全部chatGPTに聞きました