Rails Hotwire Realtime
Apply Hotwire, Turbo, Stimulus, and ActionCable best practices for real-time Rails...
Install
npx skills add marckohlbrugge/37signals-skills --skill rails-hotwire-realtime -g -a claude-code -y- Repository
- marckohlbrugge/37signals-skills730
- Category
- Engineering
- Updated
- 5mo ago
- License
- See repository
- Context cost
- Mediumabout 1,870 tokens
- Runs scripts
- No, instructions only
What it does
Apply Hotwire, Turbo, Stimulus, and ActionCable best practices for real-time Rails interfaces. Use when building Turbo Streams/Frames, Stimulus interactions, or websocket-driven updates.
Rails Hotwire + Realtime
Use for Turbo/Stimulus/ActionCable architecture and reviews. Patterns from Campfire (cable-heavy chat) and Fizzy (streams-only kanban).
Choose the Right Realtime Architecture
Two proven 37signals topologies:
- Streams-only (Fizzy): no custom ActionCable channels at all.
turbo_stream_from,broadcasts_refreshes+ morph, lazy frames with ETags. Default to this for CRUD-ish apps. - Cable-augmented (Campfire): custom channels only for lightweight JSON signals (presence, typing, unread pings) where rendering HTML server-side would be wasteful. Durable DOM state still goes through Turbo Streams.
Rule of thumb: Turbo Streams for anything that changes the DOM; bare ActionCable only for tiny ephemeral signals.
Turbo Defaults
- Prefer server-rendered partial updates over heavy client-side state systems.
- Set global morph refresh in the layout:
turbo_refreshes_with method: :morph, scroll: :preserve. - Use Turbo Streams for targeted updates; one action can render a multi-target stream template that updates every affected region atomically (source column + destination + detail pane).
- Lazy-load expensive sections with
turbo_frame_tag ..., src:, loading: :lazyand give the frame endpoint its ownfresh_whenETag. Extract frequently-changing fragments into their own frames so they don't bust the parent cache. - Use
data-turbo-permanentfor elements that must survive navigation/morph (footer trays, in-progress editors). - Block morph from clobbering client-owned state (e.g. localStorage-driven collapsed columns) via
turbo:before-morph-attribute+preventDefault(). - Exempt realtime-heavy pages from Turbo's page cache (
turbo_exempts_page_from_cache); rely on frame-level ETags instead. - Optimistic UI without a JS framework: server-render a
<template>partial with$placeholder$tokens; client clones it with a generated ID before submit; the stream response replaces it.
