You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Action Cable频道自定义方法调用:连接时获取在线用户数

解决Action Cable连接频道时获取在线用户数的问题

先给你提个醒:你现在用的@count是实例变量,每个连接到频道的用户都会生成一个独立的OnTheSamePageChannel实例,每个实例的@count都是各自独立的,所以这个统计完全不准!得先把用户数的统计逻辑改对,再实现调用自定义方法的功能。

第一步:修复在线用户数统计

单服务器场景(开发/小流量可用)

如果你的应用只跑在单台服务器上,可以用类变量@@count来共享全局计数:

class OnTheSamePageChannel < ApplicationCable::Channel
  @@count = 0

  def subscribed
    # 保留你的原有订阅逻辑
    @@count += 1
    stream_for(params[:url])
    # 订阅成功后主动推送当前用户数
    broadcast_to(params[:url], { type: 'user_count', count: @@count })
  end

  def unsubscribed
    # 保留你的原有取消订阅逻辑
    @@count -= 1
    broadcast_to(params[:url], { type: 'user_count', count: @@count })
  end

  # 遵循Ruby规范,改成蛇形命名更合适
  def nb_users
    pp 'debug: nbUsersCalled'
    # 把当前计数推送给客户端
    broadcast_to(params[:url], { type: 'user_count', count: @@count })
  end
end

多服务器/生产环境(推荐)

如果是多服务器部署,类变量会因为服务器隔离导致统计错误,这时候用Redis存全局计数才靠谱:

class OnTheSamePageChannel < ApplicationCable::Channel
  def subscribed
    url_key = "page_#{params[:url]}_online_users"
    # 自增计数
    Redis.current.incr(url_key)
    stream_for(params[:url])
    # 推送当前用户数
    broadcast_to(params[:url], { type: 'user_count', count: Redis.current.get(url_key).to_i })
  end

  def unsubscribed
    url_key = "page_#{params[:url]}_online_users"
    # 自减计数
    Redis.current.decr(url_key)
    broadcast_to(params[:url], { type: 'user_count', count: Redis.current.get(url_key).to_i })
  end

  def nb_users
    pp 'debug: nbUsersCalled'
    url_key = "page_#{params[:url]}_online_users"
    count = Redis.current.get(url_key).to_i
    # 把计数推送给客户端
    broadcast_to(params[:url], { type: 'user_count', count: count })
  end
end

第二步:客户端调用方法并接收结果

在你的JavaScript订阅代码里,订阅成功后用perform方法调用服务器的自定义方法,同时监听服务器推送的用户数数据:

export default class OnSamePageSubscription {
  constructor() {
    this.subscription = null;
  }

  subscribe(pageUrl) {
    this.subscription = App.cable.subscriptions.create(
      { channel: 'OnTheSamePageChannel', url: pageUrl },
      {
        connected() {
          console.log('已连接到频道');
        },
        subscribed() {
          // 订阅成功后调用服务器的nb_users方法
          this.perform('nbUsers');
          // 注意:Action Cable会自动将客户端驼峰名转换为服务器蛇形名,所以这里写nbUsers也能触发nb_users方法
        },
        received(data) {
          // 接收服务器推送的用户数
          if (data.type === 'user_count') {
            console.log(`当前在线用户:${data.count}人`);
            // 这里可以把计数渲染到页面DOM上
            const countElement = document.getElementById('online-user-count');
            if (countElement) countElement.textContent = data.count;
          }
        },
        disconnected() {
          console.log('已断开频道连接');
        }
      }
    );
  }
}

额外提示

  • 遵循Ruby命名规范:把服务器端的方法名改成nb_users(蛇形),客户端用this.perform('nbUsers')(驼峰),Action Cable会自动处理两者的映射,这样代码更符合社区规范。
  • 如果不需要主动调用nb_users,其实在subscribed方法里直接推送用户数就足够了,没必要额外调用方法,这样更简洁。

内容的提问来源于stack exchange,提问作者Xero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:42:04