action-cable

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

ActionCable Setup

ActionCable 搭建与使用

Overview

概述

ActionCable integrates WebSockets with Rails to enable real-time features. This guide covers the basic setup in this application.
ActionCable 将 WebSockets 与 Rails 集成,以实现实时功能。本指南介绍了在本应用中的基础配置步骤。

Core Components

核心组件

1. Connection (
app/channels/application_cable/connection.rb
)

1. 连接(
app/channels/application_cable/connection.rb

The connection authenticates and authorizes the WebSocket connection using Devise/Warden.
ruby
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def find_verified_user
      if verified_user = env['warden'].user
        verified_user
      else
        reject_unauthorized_connection
      end
    end
  end
end
该连接使用 Devise/Warden 对 WebSocket 连接进行身份验证和授权。
ruby
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def find_verified_user
      if verified_user = env['warden'].user
        verified_user
      else
        reject_unauthorized_connection
      end
    end
  end
end

2. Channel (
app/channels/application_cable/channel.rb
)

2. 频道(
app/channels/application_cable/channel.rb

Base channel class for all application channels.
ruby
module ApplicationCable
  class Channel < ActionCable::Channel::Base
  end
end
所有应用频道的基础频道类。
ruby
module ApplicationCable
  class Channel < ActionCable::Channel::Base
  end
end

3. JavaScript Setup (
app/javascript/initializers/actioncable.js
)

3. JavaScript 配置(
app/javascript/initializers/actioncable.js

Initialize ActionCable consumer on the client side.
javascript
import * as ActionCable from '@rails/actioncable'

ActionCable.logger.enabled = false
在客户端初始化ActionCable消费者。
javascript
import * as ActionCable from '@rails/actioncable'

ActionCable.logger.enabled = false

Broadcasting Updates

广播更新

With Turbo Streams (recommended)

使用Turbo Streams(推荐)

Subscribe to a stream in views:
slim
= turbo_stream_from record
= turbo_stream_from [record, "channel_name"]
Broadcast Turbo Stream updates from controllers or background jobs:
ruby
undefined
在视图中订阅流:
slim
= turbo_stream_from record
= turbo_stream_from [record, "channel_name"]
从控制器或后台任务广播Turbo Stream更新:
ruby
undefined

Append content to a target

向目标追加内容

Turbo::StreamsChannel.broadcast_append_to( [record, "channel_name"], target: "dom_id", partial: "path/to/partial", locals: { record: record } )
Turbo::StreamsChannel.broadcast_append_to( [record, "channel_name"], target: "dom_id", partial: "path/to/partial", locals: { record: record } )

Replace content

替换内容

Turbo::StreamsChannel.broadcast_replace_to( [record, "channel_name"], target: "dom_id", partial: "path/to/partial", locals: { record: record } )
Turbo::StreamsChannel.broadcast_replace_to( [record, "channel_name"], target: "dom_id", partial: "path/to/partial", locals: { record: record } )

Remove element

移除元素

Turbo::StreamsChannel.broadcast_remove_to( [record, "channel_name"], target: "dom_id" )
undefined
Turbo::StreamsChannel.broadcast_remove_to( [record, "channel_name"], target: "dom_id" )
undefined

Example: Organization-scoped notifications

示例:组织级别的通知

View:
slim
= turbo_stream_from current_organization, "timers"

#notifications
Controller:
ruby
def start_timer
  # ... create timer logic ...

  Turbo::StreamsChannel.broadcast_append_to(
    [current_organization, "timers"],
    target: "notifications",
    partial: "timers/notification",
    locals: { timer: @timer }
  )
end
视图:
slim
= turbo_stream_from current_organization, "timers"

#notifications
控制器:
ruby
def start_timer
  # ... 创建计时器逻辑 ...

  Turbo::StreamsChannel.broadcast_append_to(
    [current_organization, "timers"],
    target: "notifications",
    partial: "timers/notification",
    locals: { timer: @timer }
  )
end

Configuration

配置

Cable URL (
config/cable.yml
)

Cable 地址(
config/cable.yml

yaml
development:
  adapter: async

test:
  adapter: test

production:
  adapter: solid_cable
  connects_to:
    database:
      writing: cable
  polling_interval: 0.1.seconds
  message_retention: 1.day
yaml
development:
  adapter: async

test:
  adapter: test

production:
  adapter: solid_cable
  connects_to:
    database:
      writing: cable
  polling_interval: 0.1.seconds
  message_retention: 1.day

Routes (
config/routes.rb
)

路由(
config/routes.rb

ActionCable is automatically mounted at
/cable
:
ruby
Rails.application.routes.draw do
  mount ActionCable.server => '/cable'
end
ActionCable 会自动挂载到
/cable
路径:
ruby
Rails.application.routes.draw do
  mount ActionCable.server => '/cable'
end

Debugging

调试

Enable logging in development:
javascript
// app/javascript/initializers/actioncable.js
ActionCable.logger.enabled = true
Check connection status:
javascript
const subscription = consumer.subscriptions.create("ExampleChannel", {
  connected() {
    console.log("Connected to ExampleChannel")
  }
})

console.log(subscription)
在开发环境中启用日志:
javascript
// app/javascript/initializers/actioncable.js
ActionCable.logger.enabled = true
检查连接状态:
javascript
const subscription = consumer.subscriptions.create("ExampleChannel", {
  connected() {
    console.log("Connected to ExampleChannel")
  }
})

console.log(subscription)

Security Considerations

安全注意事项

  • Always authenticate connections in
    ApplicationCable::Connection
  • Validate params in channel subscriptions
  • Use
    stream_for
    instead of
    stream_from
    when possible for automatic scoping
  • Never trust client-side data without validation
  • Consider rate limiting for channels that accept client messages
  • 始终在
    ApplicationCable::Connection
    中对连接进行身份验证
  • 验证频道订阅中的参数
  • 尽可能使用
    stream_for
    而非
    stream_from
    以实现自动作用域
  • 未经验证绝不要信任客户端数据
  • 对接受客户端消息的频道考虑设置速率限制