Ask A Question

Notifications

You’re not receiving notifications from this thread.

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?

Reply

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.

Reply

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?

Reply

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 :)

Reply

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

Reply

I have the same issue.

Reply

I got the same error. Were you able to figure out the cause or a fix ?

Reply

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.

Reply

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?

Reply

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 ?

Reply

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)?

Reply

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.

Reply

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):

Reply

+1

Reply

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

Reply

Anything you'd do differently with Turbo Stream available now?

Reply
Join the discussion
Create an account Log in

Want to stay up-to-date with Ruby on Rails?

Join 86,946+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.