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)
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.
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
With
ActionCable.server.pubsub.send(:listener).instance_variable_get("@subscribers")
you can get map with subscription identifier in the key and array of procedures which will be executed on the broadcast. All procedures accept message as argument and have memoized connection.
来源:https://stackoverflow.com/questions/32905259/actioncable-how-to-display-number-of-connected-users