ViewComponent over Turbo Stream Broadcasts

Abstract 3D representation of an old television set, bathed in the warm, soft colors of a summer dawn, with hues of orange, pink, and light blue highlighting the nostalgic design.

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.

  1. User clicks button to generate a report. In the controller a Report is created with a status of pending;
  2. 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;
  3. 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.

Get UI & Product Engineering Insights for Rails Apps (and product updates!)

Published at . Last updated at . Have suggestions or improvements on this content? Do reach out.

UI components for Ruby on Rails apps

$ 129 one-time
payment

Get Access
  • One-time Payment

  • Access to the Entire Library

  • Built using ViewComponent

  • Designed with Tailwind CSS

  • Enhanced with Hotwire