Realtime Online User Tracking with ActionCable Discussion
How would you limit those users by tenant ( account)? Would you make the data sent to redis an array of two integers, like [1, 2] where 1 is the account.id and 2 is the user.id? Or is there a simpler way to approach this?
Hi Matt,
what about setting a different key per tenant ?
ActionCable.server.pubsub.redis_connection_for_subscriptions.sadd(
"online_users_account#{account.id}", current_user.id)
As I was facing another (but I think related) issue, storing apperance for multiple models, I store a key per model and each one has its own array.
Thanks Nathan,
I was thinking something like that as well, but I'm pretty new to how ActionCable works so am stumbling through this a bit... Good to know that I had thought through this in a decent way despite not knowing how to implement this. Do you think that it'd be good to add something to connection.rb to deal with multitenancy and whethere 'current_account' is set?
Hi,
I never worked with multy tenancy and I'm also quite new to ActionCable
so I don't really know, but my guess is you could pass an array to identified_by and identify by both current_user and current_tenant.
Then set current_tenant or reject connection if none is found.
I did some testing and the following make the current_tenant variable availble in all channels and seems to work fine.
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user, :current_tenant
def connect
self.current_user = find_verified_user
self.current_tenant = find_tenant
logger.add_tags "ActionCable", "#{current_user.class.name} #{current_user.id}"
end
protected
def find_verified_user
# some logic to find the user
end
def find_tenant
# just an example
if user.tenant.present?
user.tenant
else
reject_unauthorized_connection
end
end
end
end
Again, I never had to do that so I'm not sure about this solution but it seems to work fine.
Let me know if this i working :)
Iam not using Jumpstart and if i try to even get the members in console i get an error:
NoMethodError (undefined method `redis_connection_for_subscriptions' for #ActionCable::SubscriptionAdapter::Async:0x00007f8bc0a80ba8)
has anyone an idea why ? or how to fix
After digging around a little I noticed the problem was in cabl.yml, (Im assuming you both encountered this issue while working in development).
There is an 'adapter: async' under the development namespace, just set it to redis and that solved my problem.
have I missed something?
if a user is logged in in two browsers and then unsubscribes from only one of the browsers doesn't the unsubscribe incorrectly remove them from the redis data bas?
If I have multiple devise users scopes (Admin, User) and I plan to display the list of online Users and also the list of online Admins, should I generate 2 different channels, or should it be done in the same channel ? I am able to set the following:
identified_by :current_user, :current_admin
def connect
find_verified
end
protected
def find_verified
if (current_user = env["warden"].user(:user))
self.current_user = current_user
logger.add_tags "ActionCable", "User #{current_user.id}"
elsif (current_admin = env["warden"].user(:admin))
self.current_admin = current_admin
logger.add_tags "ActionCable", "Admin #{current_admin.id}"
else
reject_unauthorized_connection
end
end
But how should my online_channel.rb and js looks like ?
We got this working, but... just because someone is 'logged in' doesn't mean that person is online.
We use devise and it allows members to stay logged in for long periods of time, just like most websites. But that doesn't really mean someone is 'online'. In fact, it may mean someone logged in 3 days ago but hasn't had any activity since.
We originally wanted to use this to help members find other members who were online in particular chatrooms, but the way this works, it's not based on actual recent user activity, but rather 'logged in' status (which is not very accurate at all).
Anyone have any idea how to modify this so it's actually 'real time' (within 5 minutes)?
In case I was using Hotwire I would still need to use ActionCable (MyChannel.rb and MyChannel.js) I was thinking of creating an action that responds by turbo_stream with the updated partial, maybe use a job to check this by calling the action, that would make sense or would a better example? thanks.
I just implemented this and deployed it to Heroku using redistogo Nano version but I got this error:
2021-11-10T19:33:50.348851+00:00 app[web.1]: [d6a31038-f4b6-4b27-9dc3-f0db27dfd0f8] Redis::CommandError (ERR max number of clients reached):
My understanding is that when a user logs on, they are added to the online:users set. I don't know how to handle the following scenario:
- user signs in on one device
- then user signs in on another device
- then user logs out on the first device
- the :user_id would be removed from the online:users set
- now on the 2nd device, even though user is still signed in here, he wouldn't receive further notifications since his id has been removed from online:users set
How do you address this scenario?
Thanks