I'm trying to create a simple chat-like application (planning poker app) with Action Cable. I'm a little bit confused by the terminology, files hierarchy and how the callbacks work.
This is the action that creates user session:
class SessionsController < ApplicationController
def create
cookies.signed[:username] = params[:session][:username]
redirect_to votes_path
end
end
A user can then post a vote that should be broadcasted to everyone:
class VotesController < ApplicationController
def create
ActionCable.server.broadcast 'poker',
vote: params[:vote][:body],
username: cookies.signed[:username]
head :ok
end
end
Up to this point everything is clear for me and works fine. The problem is - how do I display the number of connected users? Is there a callback that fires in JS when a user (consumer?) connects? What I want is when I open 3 tabs in 3 different browsers in incognito mode I would like to display "3". When a new user connects, I would like the number to increment. If any user disconnects, the number should decrement.
My PokerChannel
:
class PokerChannel < ApplicationCable::Channel
def subscribed
stream_from 'poker'
end
end
app/assets/javascripts/poker.coffee
:
App.poker = App.cable.subscriptions.create 'PokerChannel',
received: (data) ->
$('#votes').append @renderMessage(data)
renderMessage: (data) ->
"<p><b>[#{data.username}]:</b> #{data.vote}</p>"
Seems that one way is to use
ActionCable.server.connections.length
(See caveats in the comments)
For a quick (and probably not ideal) solution you can write a module that tracks subscription counts (using Redis to store data):
#app/lib/subscriber_tracker.rb
module SubscriberTracker
#add a subscriber to a Chat rooms channel
def self.add_sub(room)
count = sub_count(room)
$redis.set(room, count + 1)
end
def self.remove_sub(room)
count = sub_count(room)
if count == 1
$redis.del(room)
else
$redis.set(room, count - 1)
end
end
def self.sub_count(room)
$redis.get(room).to_i
end
end
And update your subscribed and unsubscribed methods in the channel class:
class ChatRoomsChannel < ApplicationCable::Channel
def subscribed
SubscriberTracker.add_sub params['room_id']
end
def unsubscribed
SubscriberTracker.remove_sub params['chat_room_id']
end
end
In a related question on who is connected, there was an answer for those who uses redis:
Redis.new.pubsub("channels", "action_cable/*")
and if you just want number of connections:
Redis.new.pubsub("NUMPAT", "action_cable/*")
This will summarize connections from all your servers.
All the magic covered inside RemoteConnections class and InternalChannel module.
TL;DR all connections subscibed on special channels with a prefix action_cable/* with only purpose of disconnecting sockets from main rails app.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With