Skip to content
Back to skills

Action Cable Realtime

ASecurity

This skill should be used when the user asks about Action Cable, WebSockets,

  • 666 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 2, 2026
ai-agentsjavascriptjavarubybashrailstestingapidatabase

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Scanned September 2, 2026

npx -y skills add majiayu000/claude-skill-registry --skill action-cable-realtime --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Action Cable Realtime?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Action Cable Realtime
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-action-cable-realtime-claude-skill-registry/badge)](https://www.skillsdirectory.com/skills/majiayu000-action-cable-realtime-claude-skill-registry)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: action-cable-realtime
description: This skill should be used when the user asks about Action Cable, WebSockets,
  real-time features, channels, broadcasting, subscriptions, chat applications, live
  notifications, presence indicators, coll
---

---
name: action-cable-realtime
description: This skill should be used when the user asks about Action Cable, WebSockets, real-time features, channels, broadcasting, subscriptions, chat applications, live notifications, presence indicators, collaborative editing, server push, pub/sub patterns, Solid Cable, or streaming updates. Also use when discussing real-time architecture, WebSocket deployment, or alternatives like polling and Server-Sent Events. Examples:

<example>
Context: User wants to build a chat feature
user: "How do I build a real-time chat with Rails?"
assistant: "I'll show you how to use Action Cable channels for chat functionality."
<commentary>
This is a classic Action Cable use case involving channels and broadcasting.
</commentary>
</example>

<example>
Context: User wants live notifications
user: "How can I push notifications to users without them refreshing?"
assistant: "Action Cable broadcasts are perfect for this. Let me explain channels and subscriptions."
<commentary>
This relates to Action Cable broadcasting and real-time updates.
</commentary>
</example>

<example>
Context: User asks about deployment
user: "Do I need Redis for Action Cable in production?"
assistant: "Rails 8 includes Solid Cable which uses your database instead of Redis."
<commentary>
This involves Action Cable configuration and the Solid Cable adapter.
</commentary>
</example>
---

# Action Cable & Real-Time: WebSockets in Rails

## Overview

Action Cable integrates WebSockets with Rails, enabling real-time features like chat, notifications, and live updates. It provides both server-side Ruby and client-side JavaScript frameworks that work together seamlessly.

**Action Cable enables:**
- Real-time chat and messaging
- Live notifications
- Presence indicators (who's online)
- Collaborative editing
- Live dashboard updates
- Real-time feeds

Rails 8 introduces **Solid Cable**, which replaces Redis with database-backed pub/sub, simplifying deployment.

## Core Concepts

### WebSockets vs HTTP

**HTTP (Request-Response):**
```
Client → Request → Server
Client ← Response ← Server
[Connection closes]
```

**WebSocket (Persistent Connection):**
```
Client ↔ Persistent Connection ↔ Server
[Messages flow both directions]
[Connection stays open]
```

Benefits:
- Bi-directional communication
- Low latency (no connection overhead)
- Server can push to clients
- Efficient for real-time features

### Action Cable Architecture

```
Browser (Consumer) → WebSocket → Connection → Channels → Broadcasters
```

**Connection**: WebSocket connection (one per browser tab)
**Channel**: Logical grouping (like a controller)
**Subscription**: Consumer subscribed to a channel
**Broadcasting**: Message sent to all channel subscribers

## Channels

Channels are like controllers for WebSockets.

### Creating a Channel

```bash
rails generate channel Chat
```

Generates:

```ruby
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    # Called when consumer subscribes
    stream_from "chat_#{params[:room_id]}"
  end

  def unsubscribed
    # Called when consumer unsubscribes (cleanup)
  end

  def speak(data)
    # Called when consumer sends message
    Message.create!(
      content: data['message'],
      user: current_user,
      room_id: params[:room_id]
    )
  end
end
```

```javascript
// app/javascript/channels/chat_channel.js
import consumer from "./consumer"

consumer.subscriptions.create(
  { channel: "ChatChannel", room_id: 123 },
  {
    connected() {
      console.log("Connected to chat")
    },

    disconnected() {
      console.log("Disconnected from chat")
    },

    received(data) {
      // Handle broadcasted message
      const messagesContainer = document.getElementById("messages")
      messagesContainer.insertAdjacentHTML("beforeend", data.html)
    },

    speak(message) {
      this.perform("speak", { message: message })
    }
  }
)
```

### Streaming

Subscribe to broadcasts:

```ruby
class ChatChannel < ApplicationCable::Channel
  def subscribed
    # Stream from named channel
    stream_from "chat_room_#{params[:room_id]}"

    # Stream for current user only
    stream_for current_user

    # Stop streaming
    stop_all_streams
  end
end
```

### Channel Callbacks

Channels support lifecycle callbacks and exception handling:

```ruby
class ChatChannel < ApplicationCable::Channel
  before_subscribe :verify_access
  after_subscribe :log_subscription

  rescue_from UnauthorizedError, with: :handle_unauthorized

  def subscribed
    stream_from "chat_#{params[:room_id]}"
  end

  private

  def verify_access
    reject unless current_user.can_access?(params[:room_id])
  end

  def log_subscription
    Rails.logger.info "User #{current_user.id} subscribed to chat"
  end

  def handle_unauthorized(exception)
    # Handle error, optionally broadcast error message
    transmit(error: "Unauthorized access")
  end
end
```

Available callbacks: `before_subscribe`, `after_subscribe`, `before_unsubscribe`, `after_unsubscribe`.

## Broadcasting

Send messages to channel subscribers:

### From Models

```ruby
class Message < ApplicationRecord
  belongs_to :room
  belongs_to :user

  after_create_commit :broadcast_message

  private

  def broadcast_message
    ActionCable.server.broadcast(
      "chat_room_#{room_id}",
      {
        html: ApplicationController.render(
          partial: 'messages/message',
          locals: { message: self }
        ),
        user: user.name
      }
    )
  end
end
```

### From Controllers

```ruby
class MessagesController < ApplicationController
  def create
    @message = Message.new(message_params)

    if @message.save
      # Broadcast happens in model callback
      head :ok
    else
      render json: { errors: @message.errors }, status: :unprocessable_entity
    end
  end
end
```

### From Jobs

```ruby
class NotificationBroadcastJob < ApplicationJob
  queue_as :default

  def perform(notification)
    ActionCable.server.broadcast(
      "notifications_#{notification.user_id}",
      { html: render_notification(notification) }
    )
  end

  private

  def render_notification(notification)
    ApplicationController.render(
      partial: 'notifications/notification',
      locals: { notification: notification }
    )
  end
end
```

## Authentication

Authenticate WebSocket connections:

```ruby
# app/channels/application_cable/connection.rb
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 = User.find_by(id: cookies.encrypted[:user_id])
        verified_user
      else
        reject_unauthorized_connection
      end
    end
  end
end
```

Now `current_user` is available in all channels.

## Rails 8: Solid Cable

Solid Cable replaces Redis with database-backed pub/sub.

### Configuration

```yaml
# config/cable.yml
production:
  adapter: solid_cable
  polling_interval: 0.1  # 100ms
  message_retention: 1.day
```

```ruby
# No Redis needed!
# Solid Cable stores messages in database
# Polls for new messages every 100ms
```

### Migration

```bash
rails solid_cable:install
rails db:migrate
```

Creates `solid_cable_messages` table.

### Trade-offs

**Solid Cable:**
- Simpler deployment (no Redis)
- One database to manage
- ~100-150ms latency
- Sufficient for chat, notifications, updates

**Redis:**
- Lower latency (<50ms)
- Higher throughput
- Better for millions of connections

For most apps, Solid Cable is simpler and sufficient.

See `references/solid-cable.md` for details.

## Common Patterns

### Chat Application

```ruby
# Channel
class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_#{params[:room_id]}"
  end

  def speak(data)
    Message.create!(
      room_id: params[:room_id],
      user: current_user,
      content: data['message']
    )
  end
end

# Model
class Message < ApplicationRecord
  after_create_commit -> {
    broadcast_append_to "chat_#{room_id}",
      target: "messages",
      partial: "messages/message",
      locals: { message: self }
  }
end
```

### Live Notifications

```ruby
class NotificationChannel < ApplicationCable::Channel
  def subscribed
    stream_for current_user
  end
end

# Broadcast to specific user
NotificationChannel.broadcast_to(user, {
  html: render_notification(notification)
})
```

### Presence (Who's Online)

```ruby
class AppearanceChannel < ApplicationCable::Channel
  def subscribed
    stream_from "appearances"
    broadcast_appearance("online")
  end

  def unsubscribed
    broadcast_appearance("offline")
  end

  def appear
    broadcast_appearance("online")
  end

  def away
    broadcast_appearance("away")
  end

  private

  def broadcast_appearance(status)
    ActionCable.server.broadcast("appearances", {
      user_id: current_user.id,
      username: current_user.name,
      status: status
    })
  end
end
```

See `references/action-cable-patterns.md` for more examples.

## Testing

### Channel Tests

```ruby
require "test_helper"

class ChatChannelTest < ActionCable::Channel::TestCase
  test "subscribes to stream" do
    subscribe room_id: 42

    assert subscription.confirmed?
    assert_has_stream "chat_42"
  end

  test "receives broadcasts" do
    subscribe room_id: 42

    perform :speak, message: "Hello!"

    assert_broadcast_on("chat_42", message: "Hello!")
  end
end
```

### Integration Tests

```ruby
test "broadcasts message to chat" do
  room = rooms(:general)

  assert_broadcasts("chat_#{room.id}", 1) do
    Message.create!(room: room, user: users(:alice), content: "Hello!")
  end
end
```

## Deployment Considerations

### Standalone Server

For high-traffic apps, run Action Cable on separate servers:

```ruby
# config/cable.yml
production:
  adapter: solid_cable
  url: wss://cable.example.com
```

### Scaling

Action Cable scales horizontally:
- Multiple app servers
- Shared pub/sub (Solid Cable database or Redis)
- Load balancer with WebSocket support

### Monitoring

Track connection count, message throughput, latency, and errors.

## Alternatives to Action Cable

### Server-Sent Events (SSE)

One-way server → client:

```ruby
def stream
  response.headers['Content-Type'] = 'text/event-stream'
  response.headers['Cache-Control'] = 'no-cache'

  sse = SSE.new(response.stream)
  sse.write({ message: "Hello" })
ensure
  sse.close
end
```

**Use when:** Only server → client needed (notifications, live feeds)

### Polling

Regular HTTP requests:

```javascript
setInterval(() => {
  fetch('/api/notifications/latest')
    .then(r => r.json())
    .then(data => updateUI(data))
}, 5000)
```

**Use when:** Simple updates, low frequency, broad browser support needed

## Further Reading

For deeper exploration:

- **`references/action-cable-patterns.md`**: Chat, notifications, presence patterns
- **`references/solid-cable.md`**: Database-backed pub/sub in Rails 8

For code examples (in `examples/`):

- **`chat-channel.rb`**: Real-time chat with typing indicators
- **`notifications-channel.rb`**: User-specific push notifications
- **`presence-channel.rb`**: Online status tracking
- **`dashboard-channel.rb`**: Admin dashboard with live stats
- **`multi-room-chat.rb`**: Multiple rooms with private messages
- **`collaborative-editing.rb`**: Document editing with cursors
- **`live-feed.rb`**: Real-time feed updates

## Summary

Action Cable provides:
- **WebSocket integration** with Rails
- **Channels** for logical grouping
- **Broadcasting** to connected clients
- **Authentication** via connection identification
- **Solid Cable** for database-backed pub/sub (Rails 8)
- **Turbo Streams** integration for HTML updates

Master Action Cable and you'll build real-time features that feel magical.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.