ターボ ストリームとカスタム アクション ケーブル チャネルの接続の問題
概要
次のような erb ビューからカスタム アクション ケーブル チャネルを使用してターボ ストリーム接続をセットアップしようとしています。
ビュー
<%= turbo_stream_from "image_viewer_#{@image.id}", channel: "ImageViewerChannel", data: {image_id: @image.id} %>
<%= turbo_frame_tag "connected_users" do %>
<%= render 'connected_users', count: 0 %>
<% end %>
チャネル
class ImageViewerChannel < ApplicationCable::Channel
extend Turbo::Streams::Broadcasts, Turbo::Streams::StreamName
include Turbo::Streams::StreamName::ClassMethods
@@connected_users_count = 0
def subscribed
@@connected_users_count += 1
@image_id = params[:image_id]
stream_from "image_viewer_#{@image_id}"
broadcast_connected_users_count
end
.....
private
def broadcast_connected_users_count
ActionCable.server.broadcast(
"image_viewer_#{@image_id}",
Turbo::StreamsChannel.broadcast_replace_to(
"connected_users",
target: "connected_users",
partial: "images/connected_users",
locals: { count: @@connected_users_count }
)
)
end
しかし、接続が適切に機能しているようには見えません。redisが実行されていて、チャネルがエレバントストリーム識別子を使用して接続を正常に確立するスティミュラスコントローラーを使用して接続を受け入れていることを確認したため、私の仮定はそれが問題であるということです景色。また、@image インスタンス変数が関連するコントローラーから適切に設定されており、HTML で次の出力が生成されることも確認しました。
<turbo-cable-stream-source channel="ImageViewerChannel" data-image-id="14" signed-stream-name="ImltYWdlX3ZpZXdlcl8xNCI=--0eeda72e7a5478708717f1013f6a650e5b36c5f313a38a50a980e004a841b092"></turbo-cable-stream-source>
助けていただければ幸いです:)
編集:
さらなるデバッグを支援するために詳細を追加し、show.html.erb から他のすべてを削除して、次のようにしました。
<%= turbo_stream_from "image_viewer_#{@image.id}", channel: "ImageViewerChannel", data: {image_id: @image.id} %>
<%= tag.div id: :connected_users do %>
<%= render "images/connected_users", count: 0 %>
<% end %>
コントローラ:
def show
@image = Image.find(params[:id])
end
完全な HTML 出力:
<main class="container mx-auto mt-28 px-5 flex">
<turbo-cable-stream-source channel="ImageViewerChannel" data-image-id="15" signed-stream-name="ImltYWdlX3ZpZXdlcl8xNSI=--b6210244563c1b1182cf3b15f63f8425aae5eb267eb38660507bae79fb80e1ca"></turbo-cable-stream-source>
<div id="connected_users">
<p> Medcial Image Viewer - Connected Users: 0 </p>
</div>
</main>
アプリのログ:
Started GET "/images/15" for 127.0.0.1 at 2024-03-01 16:31:51 +0500
Processing by ImagesController#show as HTML
Parameters: {"id"=>"15"}
Image Load (0.1ms) SELECT "images".* FROM "images" WHERE "images"."id" = ? LIMIT ? [["id", 15], ["LIMIT", 1]]
↳ app/controllers/images_controller.rb:28:in `set_image'
CACHE Image Load (0.0ms) SELECT "images".* FROM "images" WHERE "images"."id" = ? LIMIT ? [["id", 15], ["LIMIT", 1]]
↳ app/controllers/images_controller.rb:22:in `show'
Rendering layout layouts/application.html.erb
Rendering images/show.html.erb within layouts/application
Rendered images/_connected_users.erb (Duration: 0.0ms | Allocations: 14)
Rendered images/show.html.erb within layouts/application (Duration: 0.3ms | Allocations: 244)
Rendered layout layouts/application.html.erb (Duration: 6.3ms | Allocations: 6107)
Completed 200 OK in 8ms (Views: 6.6ms | ActiveRecord: 0.1ms | Allocations: 7407)
Redis が実行されています:
brew services main * ] 4:30 pm
Name Status User File
postgresql@14 error 256 xyz ~/Library/LaunchAgents/[email protected]
redis started xyz ~/Library/LaunchAgents/homebrew.mxcl.redis.plist
解決策
いくつか気になる点があります。独自のターボ ストリーム チャネルを設定しましたが、依然として Turbo::StreamsChannel を通じて更新を送信しています。あなたは更新を受信するためにconnected_usersを購読していません。 Broadcast_replace_to はターボ フレームを置き換えます。つまり、最初の更新後はターゲットが存在しません。ターボ ストリームが機能するためにターボ フレームは必要ありません。
class ImageViewerChannel < ApplicationCable::Channel
include Turbo::Streams::Broadcasts
include Turbo::Streams::StreamName
@@connected_users_count = 0
def subscribed
@@connected_users_count += 1
@image_id = params[:image_id]
stream_from "image_viewer_#{@image_id}"
broadcast_connected_users_count
end
private
def broadcast_connected_users_count
# NOTE: if you `extend Turbo::Streams::Broadcasts` then you have to
# call it as a class method `ImageViewerChannel.broadcast_update_to`
broadcast_update_to(
"image_viewer_#{@image_id}", # <= this is where you're streaming from
# that's where the broadcast goes
target: "connected_users",
partial: "images/connected_users",
locals: {count: @@connected_users_count}
)
end
end
<%= turbo_stream_from "image_viewer_#{@image.id}", channel: "ImageViewerChannel", data: {image_id: @image.id} %>
<%= tag.div id: :connected_users do %>
<%= render "images/connected_users", count: 0 %>
<% end %>
Turbo::StreamsChannel から継承することもできると思います。
class ImageViewerChannel < Turbo::StreamsChannel
@@connected_users_count = 0
def subscribed
super
@@connected_users_count += 1
broadcast_connected_users_count
end
private
def broadcast_connected_users_count
ImageViewerChannel.broadcast_update_to(
verified_stream_name_from_params,
target: "connected_users",
partial: "images/connected_users",
locals: {count: @@connected_users_count}
)
end
end
アップデート
これが私が得たものです:
<turbo-cable-stream-source channel="ImageViewerChannel" data-image-id="1" signed-stream-name="ImltYWdlX3ZpZXdlcl8xIg==--e5b0cbf8cc93373099c4c70b75fe8e397096882718b43d3638649d1da1c225ee" connected=""></turbo-cable-stream-source>
<div id="connected_users">
<div> 2 </div>
</div>
Rendered images/_connected_users.html.erb (Duration: 0.1ms | Allocations: 10)
ImageViewerChannel is streaming from image_viewer_1
[ActionCable] Broadcasting to image_viewer_1: "<turbo-stream action=\"update\" target=\"connected_users\"><template><div> 2 </div>\n</template></turbo-stream>"
ImageViewerChannel is transmitting the subscription confirmation
ImageViewerChannel transmitting "<turbo-stream action=\"update\" target=\"connected_users\"><template><div> 2 </div>\n</template></turbo-stream>" (via streamed from image_viewer_1)
ImageViewerChannel transmitting "<turbo-stream action=\"update\" target=\"connected_users\"><template><div> 2 </div>\n</template></turbo-stream>" (via streamed from image_viewer_1)
そしてケーブルメッセージ:
{
"identifier": "{\"channel\":\"ImageViewerChannel\",\"signed_stream_name\":\"ImltYWdlX3ZpZXdlcl8xIg==--e5b0cbf8cc93373099c4c70b75fe8e397096882718b43d3638649d1da1c225ee\",\"image_id\":\"1\"}",
"message": "<turbo-stream action=\"update\" target=\"connected_users\"><template><div> 2 </div>\n</template></turbo-stream>"
}