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

Rails中ActionCable推送时如何为Serializer注入current_user?

我来帮你搞定这个问题!你已经通过identified_by :current_user完成了ActionCable的用户认证,其实离解决问题只差一步——把这个current_user传递给序列化器就行。这里有几个实用的方案,你可以根据自己的场景选择:

方案一:针对每个订阅用户生成个性化序列化数据

因为每个ActionCable连接都绑定了current_user,我们可以遍历所有订阅了频道的连接,为每个用户单独生成包含is_voted的序列化数据,再逐个发送:

首先修改你的序列化器,改用context来获取用户(这是AMS推荐的传递上下文的方式):

class PostSerializer < ActiveModel::Serializer
  attribute :title
  attribute :is_voted do
    # 从context中取出current_user
    voteable_ids = context[:current_user].account.votes.where(voteable_type: 'Post').map(&:voteable_id)
    voteable_ids.include? object.id
  end
end

然后在触发更新的地方(比如Post的after_update回调,或者业务逻辑里),替换原来的广播代码:

# 找到所有订阅了updates_channel的连接
UpdatesChannel.subscriptions.each do |subscription|
  next unless subscription.current_user.present? # 跳过未认证的连接

  # 用当前连接的current_user序列化帖子
  serialized_post = ActiveModelSerializers::SerializableResource.new(
    post,
    context: { current_user: subscription.current_user }
  ).as_json

  # 单独发送给这个用户的连接
  subscription.send_data({
    event: 'posts.updated',
    data: serialized_post
  }.to_json)
end

这个方案的优势是直接利用已有的连接上下文,不需要额外的频道配置;缺点是如果订阅用户较多,遍历连接会有一定性能开销,适合用户量不大的场景。

方案二:为每个用户创建独立的订阅频道

这是Rails官方推荐的个性化广播方案——给每个用户分配专属的频道,广播时直接针对用户的频道发送个性化数据:

首先修改你的Channel类,让用户订阅自己专属的频道:

class UpdatesChannel < ApplicationCable::Channel
  identified_by :current_user

  def subscribed
    # 每个用户订阅自己的专属频道
    stream_from "updates_channel_#{current_user.id}"
  end

  # 封装一个广播方法给后端调用
  def self.broadcast_post_update(post)
    # 如果你只需要推送给相关用户(比如帖子的作者或关注者),可以替换成特定用户集合
    User.find_each do |user|
      serialized_post = ActiveModelSerializers::SerializableResource.new(
        post,
        context: { current_user: user }
      ).as_json

      # 广播到该用户的专属频道
      ActionCable.server.broadcast(
        "updates_channel_#{user.id}",
        event: 'posts.updated',
        data: serialized_post
      )
    end
  end
end

然后在触发更新的地方,调用这个封装好的方法:

UpdatesChannel.broadcast_post_update(post)

这个方案的优势是扩展性更好,用户量增长时性能更稳定;缺点是需要维护用户专属频道,前端订阅时也要对应连接到自己的频道(不过这一步很简单,前端只需要在订阅时带上当前用户ID即可)。

方案三:前端本地计算is_voted(简化版)

如果你的前端已经维护了当前用户的投票记录,那可以只广播帖子的基础数据,让前端自己判断is_voted状态:

广播时只发送必要字段:

ActionCable.server.broadcast 'updates_channel', {
  event: 'posts.updated',
  data: { id: post.id, title: post.title }
}

前端收到事件后,用本地存储的用户投票ID列表,对比帖子ID来更新is_voted状态。这个方案最简单、性能最好,但前提是前端能保证投票状态的一致性,适合投票操作不频繁的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:44:01