Turbo Stream Broadcasts allows you to broadcast real-time changes (to multiple users simultaneously). It uses WebSockets (typically via ActionCable) to deliver UI elements directly from the server without requiring custom JavaScript.
It’s often confused with Turbo Stream Responses: delivering UI elements based on responses, ie. fired on controller actions.
They work essentially the same—it’s just when and from where they are send which is different.
- Turbo Stream Broadcasts: through Websockets;
- Turbo Stream Responses: through HTTP responses (eg via a controller action).
This article focuses on the former: Turbo Stream Responses. I will reference them as Turbo Streams from here.
The official Rails way to send Turbo Streams is from Active Models. I find this in most cases quite elegant!
Examples of when this useful:
- User request a report that takes a few minutes to generate: send a notification when done;
- Another user opens a specific document: broadcast to the first user who is now watching;
- User moved a card, in a kanban board, from one column to the next column.
And the list goes on!
How to broadcast ViewComponent with Turbo Streams
Out-of-the box turbo-rails supports sending partials through websockets as it’s a first-class citizen. This made it initially tricky to send ViewComponents over websockets.
This PR made it possible to send HTML as the body too.
So let’s go over the steps for the report generating example.
- User clicks button to generate a report. In the controller a
Report
is created with a status ofpending
; - Then a
turbo_stream
response is sent to the browser. Here you can use one of Rails Designer’s Empty States and replace the Create Report button with the Empty State; - When the report is created, the status changes to
ready
and a notification is sent to the user.
How to do this last step? Like so:
# app/models/report.rb
class Report < ApplicationRecord
after_update_commit :notify_user # Shortcut for `after_commit :notify_user, on: :update`
private
def notify_user
# TODO: logic to check status changed from `pending` to `ready`
broadcast_append_to(
creator,
html: ApplicationController.render(
NotificationComponent.new(
type: "success",
data: {
stacked: true,
message: "New Report Ready",
description: "''Rails Designer Intro' now available in your account.",
primary_action: {title: "View Now", path: "#"},
secondary_action: {title: "Email to me", path: "#"}
}
)
)
end
end
(The NotificationComponent
is coming from Rails Designer)
The important bits are:
- the
html
options that was introduced in this PR; ApplicationController.render
method (it allows you to render content or templates directly).
And that is all that is needed to render your (Rails Designer) ViewComponents in Turbo Streams.