ViewComponent over Turbo Stream Broadcasts
Tags: webdev, rails, hotwire, ruby
Published: 2024-04-18 17:00:00

This article was originally published on [Rails Designer](https://railsdesigner.com/viewcomponents-in-turbo-streams/)

---

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.


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](https://railsdesigner.com/components/notifications/) 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](https://github.com/hotwired/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](https://github.com/hotwired/turbo-rails/pull/245) made it possible to send html as the body now 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. After a successful create a `turbo_stream` response is send to the browser. Here you can send one of Rails Designer's [Empty States](/components/empty-states/#loading-state) and replace the **Create Report** button with the Empty State.
3. Then once the report is created, the status changes to `ready` and a [notification](/components/notifications/) is send to the user.

How to do this last step? Like so:

```ruby
# 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](https://railsdesigner.com/components/notifications/).)

The important bits are:

- the `html` options that was introduced in [this PR](https://github.com/hotwired/turbo-rails/pull/245)
- `ApplicationController.render` method (it allows you to render content or templates directly)

And that is all what is needed to render your (Rails Designer) ViewComponents.