Actioncable 计数订阅

Posted

技术标签:

【中文标题】Actioncable 计数订阅【英文标题】:Actioncable count subscriptions 【发布时间】:2019-03-19 07:46:22 【问题描述】:

在我的 Ruby on Rails 项目中,我有一个门票 MVC。用于编辑工单(例如 ID 为 5 的工单)的典型页面是 /tickets/5/edit

在另一个页面上,我有一个简单的表格,我想实时显示每张票有多少用户正在查看(即显示有多少用户在/tickets/1/edittickets/2/edit ....

每当用户登录并在/tickets/:id/edit 上查看票证时,我都有一个咖啡脚本ticket_notifications.coffee,看起来像:

$ ->
  if $('body').attr('data-controller') == 'tickets' && $('body').attr('data-action') == 'edit'
    ticketId = document.getElementById('ticket_id').value
    App.ticket_notifications = App.cable.subscriptions.create channel: "TicketNotificationsChannel", ticket_id: ticketId,
      connected: ->
# Called when the subscription is ready for use on the server
      disconnected: ->
# Called when the subscription has been terminated by the server
      received: (data) ->

我的app/channels/ticket_notifications_channel.rb 看起来像:

class TicketNotificationsChannel < ApplicationCable::Channel
  def subscribed
    # stream_from "some_channel"
    if current_user&.account
      stream_from "ticket_notifications_channel_#current_user.account_id"
      if params[:ticket_id]
        if Ticket.find(params[:ticket_id]).account == current_user.account
          ActionCable.server.broadcast "ticket_notifications_channel_#current_user.account_id",
                                       stuff: "Agent #current_user.email is viewing ticket #params[:ticket_id]"
        end
      end
    end
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
end

前端表长这样(我用的是Slim,不过和erb差不多):

table.table.table-hover
            thead
              tr
                th
                  | Ticket #
                th
                  | Short Code
                th
                  | Mobile Number
                th
                  | Number of Tickets
                th
                  | Updated At
                th
                  | Viewers
            tbody
              - unless @tickets.empty?
                - current_time = Time.now
                - @tickets.each do |tkt|
                  - tkt_updated_at = tkt.updated_at
                  tr.m-unread.m-tr-clickable data-href=edit_ticket_path(id: tkt.id)
                    td
                      b #tkt.id
                    td
                      b #tkt.short_code
                    td
                      b #tkt.mobile_number
                    td
                      - if last_message = tkt.messages&.last&.body
                        b #last_message[0..60]
                    td
                      - if (current_time-tkt_updated_at) <= time_period
                        b #time_ago_in_words(tkt_updated_at) ago
                      - else
                        b #tkt_updated_at.in_time_zone.strftime('%b %e %H:%M:%S %Y')
                    td
                      b Count how many subscriptions to tickets_notifications channel with params tkt.id here. 

谢谢。

【问题讨论】:

你的问题是......?您是否正在尝试计算订阅或用户(并不总是相同的东西,也不应该是相同的东西)?到目前为止,您尝试了哪些代码?你被困在哪里了? 【参考方案1】:

您可以查看以下问题的答案:

How do I find out who is connected to ActionCable?

基本上你必须这样做。

Redis.new.pubsub("channels", "action_cable/*")

这将为您提供所有活动的 pubsub 频道。

您还可以在创建新订阅时提供 userId 以及 ticketId,例如:

App.cable.subscriptions.create channel: "TicketNotificationsChannel", ticket_id: ticketId, user_id: userId

所以现在Redis.new.pubsub("channels", "action_cable/*") 将通过以下方式为您提供所有有效订阅

["action_cable/Z2lkOi8vYXBpL1VzZXIvMTUwMjIz", "action_cable/Z2lkOi8vYXBpL1VzZXIvMTUwNTc0"]

对上面提到的字符串执行Base64.decode 将以以下方式为您提供输出"gid://api/User/150223/Ticket/1"。然后,您可以在此输出上构建一些逻辑,以计算特定票证 ID 的所有用户。

【讨论】:

请注意:通过添加包含用户 ID 的通道,您可能会增加 Redis 服务器的开销 - 特别是如果同时使用 Redis 的模式匹配。但是,如果没有这些通道,您将无法获得可靠的用户数量,因为单个进程/机器应该(理论上)使用单个 Redis 连接,从而使整个进程/机器成为单个订阅者。恕我直言,我会考虑在数据库中使用一个简单的计数器(它将具有两个连接的单个用户计为两个用户)或数据库中用户名的引用计数列表(这更复杂)。

以上是关于Actioncable 计数订阅的主要内容,如果未能解决你的问题,请参考以下文章

Ruby on Rails 5 Action Cable:当前模型实例的流(基于 URL 的订阅)

订阅 Action Cable 频道时如何设置参数

在 ActionCable 中找不到订阅类“MyChannel”

ActionCable出现“未找到订阅类”问题

无法理解使用带有 graphql-ruby gem 的 ActionCable 的 GraphQL 订阅

子域而不是子目录上的 ActionCable