Skip to content
Back to skills

Turbo Streams Patterns

ASecurity

Build targeted Turbo Streams correctly — model broadcasts over Action Cable, custom stream actions, authorized stream channels, and Kredis presence. Use when adding real-time/live updates (chat append, replace a card, toggle a class), writing a custom turbo-stream action, securing who can subscribe to a record's broadcasts, or debugging a stream that does nothing / a custom action that's ignored / broadcasts leaking to the wrong user. The surgical complement to the morph page-refresh model (s...

  • 3 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 6, 2026
developmentrubybashrailsdebuggingbackendsecurity

Works with

  • cli

Security analysis

A100/100

Pro scans all 6 files and shows the line behind each finding

Scanned September 6, 2026

npx -y skills add davidteren/hotwire-codex-skills --skill turbo-streams-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Turbo Streams Patterns?

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

Security grade badge for Turbo Streams Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/davidteren-turbo-streams-patterns/badge)](https://www.skillsdirectory.com/skills/davidteren-turbo-streams-patterns)

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: turbo-streams-patterns
description: Build targeted Turbo Streams correctly — model broadcasts over Action Cable, custom stream actions, authorized stream channels, and Kredis presence. Use when adding real-time/live updates (chat append, replace a card, toggle a class), writing a custom turbo-stream action, securing who can subscribe to a record's broadcasts, or debugging a stream that does nothing / a custom action that's ignored / broadcasts leaking to the wrong user. The surgical complement to the morph page-refresh model (see turbo-morphing).
---

# Targeted Turbo Streams

Surgical DOM updates: broadcast/render specific `<turbo-stream>` actions against
specific ids. Use this when you need precision (append a chat message, replace one
card, move a class); use **`turbo-morphing`** when a whole-page refresh-with-morph is
simpler. Full patterns: [`references/turbo-streams-guide.md`](references/turbo-streams-guide.md).

## When to use

- Live updates: model change → broadcast a partial to subscribers.
- A custom stream action Turbo doesn't ship (e.g. `switch_class`).
- A record's broadcasts are **private** — only authorized users may subscribe.
- Debugging: a stream that does nothing, a custom action the client ignores, or
  broadcasts arriving for the wrong user.

## Patterns (and their footguns)

1. **Model broadcast**: `after_create -> { broadcast_append_later_to parent, target:,
   partial: }`. The `_later` variants enqueue a job — **need an Active Job backend**.
   View subscribes with `turbo_stream_from parent, channel: "FooChannel"`.

2. **Authorize the stream** (security): `turbo_stream_from` only *signs* the stream
   name — it does NOT prove this user may receive that record's broadcasts. Use a
   custom channel that authorizes and `reject`s otherwise
   (`templates/authorized_channel.rb.tmpl`). The default `Turbo::StreamsChannel`
   streams from any signed name with no per-record check → eavesdropping risk.

3. **Custom stream action** = two halves that MUST match: a JS `StreamActions.X` and a
   Ruby helper registered via `Turbo::Streams::TagBuilder.prepend`
   (`templates/custom_stream_action*.tmpl`). One side alone fails silently.

4. **Stream tags inside a frame response**: to patch an element *outside* the frame
   you're rendering into, embed `turbo_stream.*` tags in the frame's HTML — no
   separate `*.turbo_stream.erb` needed.

5. **Kredis presence**: a `kredis_set` of online users (maintained in the channel's
   `subscribed`/`unsubscribed`) decides live-append vs also notifying/emailing.

## Lint an app

```bash
scripts/lint_turbo_streams.sh path/to/rails-app
```

Flags: custom stream actions wired on only one side; **channels that `stream_from`
without authorizing the subscriber** (broadcast eavesdropping — reported as an error);
`broadcast_*_later` without a job backend; and (response-stream path) a `*.turbo_stream.erb`
template whose literal slash-pathed `partial:` resolves to no file (→ `MissingTemplate`
when that stream renders) or a custom `turbo_stream.<action>` with no client-side
`StreamActions.<action>`. Heuristic grep scan (names its ceiling — bare/dynamic partials
and target-id existence aren't resolved). Verified: clean on the Piazza app and on a real
response-template app (miela_app, 14 templates), flags a synthetic leaky-channel +
half-wired + dangling-partial app.

Files in this skill

  • SKILL.md3.3 KB
  • references/turbo-streams-guide.md4.8 KB
  • scripts/lint_turbo_streams.sh6.4 KB
  • templates/authorized_channel.rb.tmpl1.2 KB
  • templates/custom_stream_action.js.tmpl669 B
  • templates/custom_stream_action_helper.rb.tmpl636 B

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.