Andrey Chernih
Andrey Chernih

Reputation: 3863

How to transmit initial payload to the client in ActionCable subscribed callback?

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

Answers (2)

Jin.X
Jin.X

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

ollpu
ollpu

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

Related Questions