Reputation: 3863
I have Ruby on Rails application which is using ActionCable for real-time client communication. I have ScoreChannel
which is responsible for streaming user score updates:
class ScoreChannel < ApplicationCable::Channel
def self.broadcast_name(user:)
"score_#{user.guid}"
end
def broadcast_name
self.class.broadcast_name(user: current_user)
end
def subscribed
stream_from(broadcast_name)
ActionCable.server.broadcast(broadcast_name, Cable::V1::ScoreSerializer.new(current_user).as_json)
end
end
I am trying to send user's current score right after a user subscribes to the channel (see ScoreChannel#subscribed
method). Unfortunately, due to asynchronous nature of ActionCable, score broadcast goes before user subscribes to the ScoreChannel
. Therefore user does not receive the initial score payload (because he is not subscribed to this channel yet). This is redis monitor timeline:
1472430005.884742 [1 172.18.0.6:50242] "subscribe" "action_cable/Z2lkOi8vYXBwLWVuZ2luZS9Vc2VyLzE"
1472430010.988077 [1 172.18.0.6:50244] "publish" "score_cc112e3fdfb5411a965a31f9468abf98" "{\"score\":17,\"rank\":1}"
1472430010.988773 [1 172.18.0.6:50242] "subscribe" "score_cc112e3fdfb5411a965a31f9468abf98"
What is the best way to solve this?
Upvotes: 1
Views: 1401
Reputation: 118
use transmit
inside a channel class/instance, ref ActionCable::Channel::Base#transmit
use broadcast
outside channel class, ref ActionCable::Server#broadcast
Upvotes: 0
Reputation: 1873
Instead of using ActionCable.server.broadcast
to broadcast to the existing subscribers, try using the transmit
-method, like this:
transmit(Cable::V1::ScoreSerializer.new(current_user).as_json)
This only sends the status to the current subscriber being handled, but I figured this is what you wanted.
Upvotes: 2