長文失礼いたします。。
ActionCableを利用し非同期のチャットを実装したいのですが、上手くいきません。色々記事を参照し2日間ほど取り組んだのですが、なぜ表示されないのか問題が特定できず困っております。
チャットの機能とは、任意のユーザ二人が参加できるTaimen/show.html.erbファイル内で、中間テーブルであるTchatテーブルにレコードを追加しそれを表示してチャットができるようにするというものです。
(1対1という意味でタイマンという言葉をローマ字にしてscaffoldしたらコントローラがtaimen_controllerになった笑)
使用しているファイルは以下の7個です。
view/taimen/show.html.erb view/taimien/_tchat.html.erb assets/javascript/channels/consumer.js assets/javascript/channels/taiman_room.js channels/application_cable/connection.rb channels/taiman_channel.rb jobs/tchat_broadcast_job.rb
【問題として可能性があるのは】
・サブスクライブできていない?
→taiman_channel.rbでは、コンシューマがTaimanテーブルにあるすべてのレコードについて、それぞれサブスクライブされるように指定したいのですが、この定義が間違えている可能性があります。taiman_room.jsファイル内でconsumer.subscriptions.create("TaimanChannel" という記述があるのですが、ここで引数を指定しchannelを判別する記事を見かけたのですが、それをしないで済むようにtaiman_channel.rb内で記述しています。
・データがviewファイルに反映されていない?
→コメントしたデータがDBに保存され、tchat_broad_cast.jobに飛んでいることは確認しています。そこで、ブロードキャストを実行しているtchat_broad_cast.jobファイルでブロードキャストが失敗していて、taiman_room.jsファイル内のrecievedメソッドにデータが飛んでいない、あるいはそこのデータは飛んでいるが、recievedメソッドからviewファイルにデータが飛ばせていないかのいずれかが問題だと思います。
【疑いをまとめると】
1そもそもサブスクリプション出来ているのか?
2ブロードキャスト出来ているのか?
3viewに表示できているのか?
の3点になります。
これらを検証する方法、又もしよろしければコードもご覧頂き具体的な修正箇所もご指摘頂けると幸いです。
普通の質問に比べコードの量も多いので、画面共有しながらご指摘頂くなど大歓迎です。
何卒よろしくお願い申し上げます。
view/taimen/show.html.erb
<!-- タイマンチャットエリア --> <div class="chats"> <ul id="tchat> <% @chats.each do |c| %> <% if c.user_id == @taiman.p1_id %> <br><li class="p1_chats" id='list'><%= c.body %></li> <% else %> <br><li class="p2_chats" id='list'><%= c.body %></li> <% end %> <% end %> <%= render partial: "/taimen/tchat" %> <!-- 自動スクロールのためのアンカー --> <li id="last" class="last"></li> </ul> </div> </div> <!-- タイマン発言フォーム --> <% if @current_user %> <% if @current_user.id == @taiman.p1_id || @current_user.id == @taiman.p2_id %> <%= form_tag("/tchats/#{@taiman.id}/create") do %> <div class="battle_chatbox"> <textarea name="body" rows="1" cols="80"></textarea> <input type="submit" id= "send" value="送信"> </div> <% end %> <% end %> <% end %>
view/taimien/_tchat.html.erb
<li> tchat.body </li>
assets/javascript/channels/consumer.js
// app/javascript/channels/consumer.js // Action CableはRailsでWebSocketを扱うフレームワークを提供する // WebSocketがある場所で`bin/rails generate channel`コマンドを使うと新しいチャネルを生成できる import { createConsumer } from "@rails/actioncable" export default createConsumer() //localhost createConsumer("http://localhost:3000/cable")
assets/javascript/channels/taiman_room.js
import consumer from "./consumer" // 「const appRoom =」を追記 // createの引数にidをいれるべきか // 引数はtaiman channelでparamsで受け取ることができる consumer.subscriptions.create("TaimanChannel", { // 省略 received(data) { const tchat = document.getElementById('tchat'); tchat.insertAdjacentHTML('beforeend', data['tchat']); }, speak: function(tchat) { // ここでBroadcast呼び出し return this.perform('speak', {body: tchat}); } });
channels/application_cable/connection.rb
module ApplicationCable class Connection < ActionCable::Connection::Base identified_by :@current_user def connect @current_user = User.find_by(id: session[:id]) end end end
channels/taiman_channel.rb
class TaimanChannel < ApplicationCable::Channel def subscribed #taiman = Taiman.find(params[:id]) #strem_from "taimen_#{params[:id]}" #stream_forとstream_fromの違い???? #stream_for taiman #stream_from "taiman_1" Taiman.all.each do |taiman| stream_for taiman end end def unsubscribed # Any cleanup needed when channel is unsubscribed end def speak(data) # 引数でBroadcast先を指定できる(taiman id ) #ActionCable.server.broadcast 'taiman_channel', body: data['tchat'] #TaimanChannel.Broadcast_to(@taiman, @chats) #Tchat.create! body: data['tchat'] end document.getElementById("#").onclick = function(e) { appRoom.speak(e.target.value); e.target.value = ''; e.preventDefault(); }; end
jobs/tchat_broadcast_job.rb
class TchatBroadcastJob < ApplicationJob queue_as :default def perform(tchat) ActionCable.server.broadcast "taiman_channel",{ tchat: render_message(tchat)} #TaimanChannel.broadcast "taiman_channel", tchat:tchat # Do something later end private def render_message(tchat) ApplicationController.renderer.render(partial: 'taimen/tchat', locals: { tchat: tchat }) end end
0 コメント