ActionCable - how to display number of connected users?
Seems that one way is to use
ActionCable.server.connections.length
(See caveats in the comments)
Actioncable connected users list
Ya kinda have to roll your own user-tracking.
The important bits are as follows:
# connection
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :uid
def connect
self.uid = get_connecting_uid
logger.add_tags 'ActionCable', uid
end
protected
# the connection URL to this actioncable/channel must be
# domain.tld?uid=the_uid
def get_connecting_uid
# this is just how I get the user id, you can keep using cookies,
# but because this key gets used for redis, I'd
# identify_by the user_id instead of the current_user object
request.params[:uid]
end
end
end
# Your Channel
def subscribed
stop_all_streams
stream_from broadcasting_name
ConnectedList.add(uid)
end
def unsubscribed
ConnectedList.remove(uid)
end
And then in Models:
class ConnectedList
REDIS_KEY = 'connected_nodes'
def self.redis
@redis ||= ::Redis.new(url: ActionCableConfig[:url])
end
# I think this is the method you want.
def self.all
redis.smembers(REDIS_KEY)
end
def self.clear_all
redis.del(REDIS_KEY)
end
def self.add(uid)
redis.sadd(REDIS_KEY, uid)
end
def self.include?(uid)
redis.sismember(REDIS_KEY, uid)
end
def self.remove(uid)
redis.srem(REDIS_KEY, uid)
end
end
from: https://github.com/NullVoxPopuli/mesh-relay/
Detect Action Cable connection status
Got it sorted out. In my components, when I need to find out cable status, I do
this.$root.cable.connection.isOpen()
If false I revert to HTTP.
Hope this helps someone later on.
Get list of all registered connections
I finally found a solution.
def connect
self.uuid = SecureRandom.uuid
transmit({'title': 'players_online', 'message': ActionCable.server.connections.size + 1})
ActionCable.server.connections.each do |connection|
connection.transmit({'title': 'players_online', 'message': ActionCable.server.connections.size + 1})
end
end
def disconnect
transmit({'title': 'players_online', 'message': ActionCable.server.connections.size})
ActionCable.server.connections.each do |connection|
connection.transmit({'title': 'players_online', 'message': ActionCable.server.connections.size})
end
end
ActionCable.server.connections
gets a list of all server connection, except of the one which is currently connecting to the socket. That's why you need to transmit him a message directly with ActionCable.server.connections.size + 1
How do I get current_user in ActionCable rails-5-api app?
If you see the doc you provided, you will know that identified_by
is not a method for a Channel
instance. It is a method for Actioncable::Connection
.
From Rails guide for Actioncable Overview, this is how a Connection
class looks like:
#app/channels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
end
private
def find_verified_user
if current_user = User.find_by(id: cookies.signed[:user_id])
current_user
else
reject_unauthorized_connection
end
end
end
end
As you can see, current_user
is not available here. Instead, you have to create a current_user
here in connection.
The websocket server doesn't have a session, but it can read the same cookies as the main app. So I guess, you need to save cookie after authentication.
ActionCable display correct number of connected users (problems: multiple tabs, disconnects)
I finally at least got it to work for counting all users to the server (not by room) by doing this:
CoffeeScript of my channel:
App.online_status = App.cable.subscriptions.create "OnlineStatusChannel",
connected: ->
# Called when the subscription is ready for use on the server
#update counter whenever a connection is established
App.online_status.update_students_counter()
disconnected: ->
# Called when the subscription has been terminated by the server
App.cable.subscriptions.remove(this)
@perform 'unsubscribed'
received: (data) ->
# Called when there's incoming data on the websocket for this channel
val = data.counter-1 #-1 since the user who calls this method is also counted, but we only want to count other users
#update "students_counter"-element in view:
$('#students_counter').text(val)
update_students_counter: ->
@perform 'update_students_counter'
Ruby backend of my channel:
class OnlineStatusChannel < ApplicationCable::Channel
def subscribed
#stream_from "specific_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
#update counter whenever a connection closes
ActionCable.server.broadcast(specific_channel, counter: count_unique_connections )
end
def update_students_counter
ActionCable.server.broadcast(specific_channel, counter: count_unique_connections )
end
private:
#Counts all users connected to the ActionCable server
def count_unique_connections
connected_users = []
ActionCable.server.connections.each do |connection|
connected_users.push(connection.current_user.id)
end
return connected_users.uniq.length
end
end
And now it works! When a user connects, the counter increments, when a user closes his window or logs off it decrements. And when a user is logged on with more than 1 tab or window they are only counted once. :)
Related Topics
How to Make a Post Request with Open-Uri
What Is '-Mix' in a Ruby Regular Expression
How to Calculate How Many Years Passed Since a Given Date in Ruby
Rails Date Format in Form Field
Sinatra Clears Session on Post
Chaining Methods Using Symbol#To_Proc Shorthand in Ruby
Add Space After Commas Only If It Doesn't Already
Rack::Request - How to Get All Headers
How to Get a Particular Line from a File
How to Extract the Code from a Proc Object
Invalid Gemspec -Illformed Requirement ["#<Yaml::Syck::Defaultkey:0Xb5F9C990> 3.2.0"]