0

I'm trying to implement action cable. This is working well, but I want, when I'm connecting to a channel, to receive some data (here I want to know how many users are connected yet).

I created on my channel a custom method nbUsers :

class OnTheSamePageChannel < ApplicationCable::Channel

  @count = 0

  def subscribed
    ...
    @count++
    stream_for(params[:url])
  end

  def unsubscribed
    ...
    @count--
  end

  def nbUsers
    pp 'debug: nbUsersCalled'
    @count
  end

And my javascript :

export default class OnSamePageSubscription extends React.Component {

    constructor(props) {
        super(props);

        this.cable = ActionCable.createConsumer(WEB_SOCKET_HOST);
        this.subscribe = () => {
            this.channel = this.cable.subscriptions.create(
                {
                    channel: 'OnTheSamePageChannel',
                    url: props.url,
                    current_user: props.current_user
                },
                {
                    connected: this.connected,
                    disconnected: this.disconnected,
                    received: this.received,
                    rejected: this.rejected
                }
            );
        };
        this.unsubscribe = () => {
            this.channel.unsubscribe()
        };
    }

    received = (data) => {
        console.log(`Connected user : ${data.user}`);

        this.props.onUpdate(data);
    };

    connected = () => {
        console.log(`Tracking connection`);
    };

    disconnected = () => {
        console.warn(`Tracking disconnected.`);
    };

    rejected = () => {
        console.warn('Tracking rejected');
    };

}

The question is : how to call this method (nbUsers) and getting result ?

I tried https://robots.thoughtbot.com/talking-to-actioncable-without-rails but this is not working

Xero
  • 3,951
  • 4
  • 41
  • 73

2 Answers2

1

You can call it using perform. Here is the code this.perform("nbUsers")

abhi110892
  • 300
  • 1
  • 7
1
class OnTheSamePageChannel < ApplicationCable::Channel

  @count = 0

  def subscribed
    # ...
    @count++
    stream_for(params[:url])
    transmit(number_of_users: nbUsers)
  end
  # ...
end


export default class OnSamePageSubscription extends React.Component {
  // ...
  received = (data) => {
    console.log(`Number of users: ${data.number_of_users}`);

    this.props.onUpdate(data);
  };
}
  • Above is a direct answer to your question...

    how to call this method (nbUsers) and getting result ?

    ...however, there are still lots of problems in your current code:

    • class OnTheSamePageChannel < ApplicationCable::Channel
        @count = 0 
        # ^ this is a class-level instance-variable
        # ...and not an instance-level instance-variable (that I think you were under the impression of
      end
      
      # To demonstrate:
      # OnTheSamePageChannel.new.instance_variable_get(:@count)
      # => nil
      # OnTheSamePageChannel.instance_variable_get(:@count)
      # => 0
      
    • To fix this, you'll want to do something like:

      class OnTheSamePageChannel < ApplicationCable::Channel
        attr_accessor :count
        @count = 0 
      
        def subscribed
          # ...
          self.class.count += 1
        end
      
        def unsubscribed 
          # ...
          self.class.count -= 1
        end
      
        def nbUsers
          # ...
          self.class.count
        end
      end
      
    • IMPORTANT: the code just above will only work on single-process server, it won't fully work if you already have multiple servers or processes, or other rails-dependent applications like Sidekiq or (rails-console) precisely just because memory (of which @count is stored) is not shared between them. As far as I know, there is not (yet?) a simple built-in Rails way to check the number of connected users if "scaling" is already taken into account. Feel free to check some other SO question

Jay-Ar Polidario
  • 6,463
  • 14
  • 28