$npx -y skills add ThibautBaissac/rails_ai_agents --skill action-cable-patternsImplements real-time features with Action Cable and WebSockets. Use when adding live updates, chat features, notifications, real-time dashboards, or when user mentions Action Cable, WebSockets, channels, or real-time. WHEN NOT: Simple HTTP request/response flows, REST APIs, stati
| 1 | # Action Cable Patterns for Rails 8 |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Action Cable integrates WebSockets with Rails: |
| 6 | - Real-time updates without polling |
| 7 | - Server-to-client push notifications |
| 8 | - Chat and messaging features |
| 9 | - Live dashboards and feeds |
| 10 | - Collaborative editing |
| 11 | |
| 12 | ## Quick Start |
| 13 | |
| 14 | Action Cable is included in Rails by default. Configure it: |
| 15 | |
| 16 | ```ruby |
| 17 | # config/cable.yml |
| 18 | development: |
| 19 | adapter: async |
| 20 | |
| 21 | test: |
| 22 | adapter: test |
| 23 | |
| 24 | production: |
| 25 | adapter: solid_cable # Rails 8 default |
| 26 | # OR |
| 27 | adapter: redis |
| 28 | url: <%= ENV.fetch("REDIS_URL") %> |
| 29 | ``` |
| 30 | |
| 31 | ## Project Structure |
| 32 | |
| 33 | ``` |
| 34 | app/ |
| 35 | ├── channels/ |
| 36 | │ ├── application_cable/ |
| 37 | │ │ ├── connection.rb # Authentication |
| 38 | │ │ └── channel.rb # Base channel |
| 39 | │ ├── notifications_channel.rb |
| 40 | │ ├── events_channel.rb |
| 41 | │ └── chat_channel.rb |
| 42 | ├── javascript/ |
| 43 | │ └── channels/ |
| 44 | │ ├── consumer.js |
| 45 | │ ├── notifications_channel.js |
| 46 | │ └── events_channel.js |
| 47 | spec/channels/ |
| 48 | ├── notifications_channel_spec.rb |
| 49 | └── events_channel_spec.rb |
| 50 | ``` |
| 51 | |
| 52 | ## Connection Authentication |
| 53 | |
| 54 | ```ruby |
| 55 | # app/channels/application_cable/connection.rb |
| 56 | module ApplicationCable |
| 57 | class Connection < ActionCable::Connection::Base |
| 58 | identified_by :current_user |
| 59 | |
| 60 | def connect |
| 61 | self.current_user = find_verified_user |
| 62 | end |
| 63 | |
| 64 | private |
| 65 | |
| 66 | def find_verified_user |
| 67 | # Using Rails 8 authentication |
| 68 | if session_token = cookies.signed[:session_token] |
| 69 | if session = Session.find_by(token: session_token) |
| 70 | session.user |
| 71 | else |
| 72 | reject_unauthorized_connection |
| 73 | end |
| 74 | else |
| 75 | reject_unauthorized_connection |
| 76 | end |
| 77 | end |
| 78 | end |
| 79 | end |
| 80 | ``` |
| 81 | |
| 82 | ## Channel Patterns |
| 83 | |
| 84 | Four core patterns are available. See [channel-patterns.md](references/channel-patterns.md) for full Ruby and JavaScript implementations: |
| 85 | |
| 86 | - **Pattern 1: Notifications Channel** — streams per-user notifications via `stream_for current_user` |
| 87 | - **Pattern 2: Resource Updates Channel** — streams updates for a specific resource with authorization via `reject` |
| 88 | - **Pattern 3: Chat Channel** — bidirectional messaging with `speak` and `typing` actions, presence tracking |
| 89 | - **Pattern 4: Dashboard Live Updates** — broadcasts stats and activity feed to all account members |
| 90 | |
| 91 | Each pattern follows the same structure: |
| 92 | 1. `subscribed` — find the resource, check authorization, call `stream_for` |
| 93 | 2. Class-level `broadcast_*` methods — render partials via `ApplicationController.renderer` |
| 94 | 3. A matching JavaScript subscription handler with a `received(data)` switch |
| 95 | |
| 96 | ## Broadcasting |
| 97 | |
| 98 | Broadcasting can be triggered from services, models, or callbacks. See [broadcasting-and-stimulus.md](references/broadcasting-and-stimulus.md) for: |
| 99 | |
| 100 | - **From a service object** — call `EventsChannel.broadcast_update(event)` after persistence |
| 101 | - **From model callbacks** — use `after_create_commit` to trigger channel broadcasts |
| 102 | - **Turbo Streams integration** — use `broadcast_append_to` / `broadcast_remove_to` helpers directly on models |
| 103 | - **Stimulus controller** — wrap the Action Cable subscription lifecycle inside a Stimulus controller for clean connect/disconnect management |
| 104 | - **Performance patterns** — connection limits, selective broadcasting, debounced broadcasts |
| 105 | |
| 106 | ## Testing Channels |
| 107 | |
| 108 | See [testing.md](references/testing.md) for full specs. Key conventions: |
| 109 | |
| 110 | ```ruby |
| 111 | # Stub connection identity |
| 112 | stub_connection(current_user: user) |
| 113 | |
| 114 | # Assert subscription confirmed and streaming |
| 115 | subscribe(event_id: event.id) |
| 116 | expect(subscription).to be_confirmed |
| 117 | expect(subscription).to have_stream_for(event) |
| 118 | |
| 119 | # Assert rejection for unauthorized access |
| 120 | expect(subscription).to be_rejected |
| 121 | |
| 122 | # Assert broadcast payload |
| 123 | expect { |
| 124 | described_class.notify(user, notification) |
| 125 | }.to have_broadcasted_to(user).with(hash_including(type: "notification")) |
| 126 | ``` |
| 127 | |
| 128 | ## Checklist |
| 129 | |
| 130 | - [ ] Connection authentication configured |
| 131 | - [ ] Channel authorization implemented |
| 132 | - [ ] Client-side subscription set up |
| 133 | - [ ] Broadcasting from services/models |
| 134 | - [ ] Channel specs written |
| 135 | - [ ] Error handling in place |
| 136 | - [ ] Reconnection logic on client |
| 137 | - [ ] Performance limits configured |
| 138 | |
| 139 | ## References |
| 140 | |
| 141 | - [channel-patterns.md](references/channel-patterns.md) — Full implementations of Notifications, Resource Updates, Chat, and Dashboard channels (Ruby + JavaScript) |
| 142 | - [broadcasting-and-stimulus.md](references/broadcasting-and-stimulus.md) — Broadcasting from services/models, Turbo Streams integration, Stimulus controller, performance tips |
| 143 | - [testing.md](references/testing.md) — RSpec channel specs, authorization specs, and system tests |