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
相关产品推荐
相关产品推荐

