action-cable

Original🇺🇸 English
Translated

Setup and use ActionCable for real-time features in Rails applications using WebSockets. Use when implementing real-time updates, live notifications, broadcasting changes, or when the user mentions WebSockets, ActionCable, channels, broadcasting, or Turbo Streams over cable.

5installs
Added on

NPX Install

npx skill4agent add rolemodel/rolemodel-skills action-cable

Tags

Translated version includes tags in frontmatter

ActionCable Setup

Overview

ActionCable integrates WebSockets with Rails to enable real-time features. This guide covers the basic setup in this application.

Core Components

1. Connection (
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

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

Base channel class for all application channels.
ruby
module ApplicationCable
  class Channel < ActionCable::Channel::Base
  end
end

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

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

ActionCable.logger.enabled = false

Broadcasting Updates

With Turbo Streams (recommended)

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
# Append content to a target
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 }
)

# Remove element
Turbo::StreamsChannel.broadcast_remove_to(
  [record, "channel_name"],
  target: "dom_id"
)

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

Configuration

Cable URL (
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

Routes (
config/routes.rb
)

ActionCable is automatically mounted at
/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)

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