module Broadcastable
Ruby on Rails 2.0.23
Since v1.3.3 Last seen in v2.0.23Turbo streams can be broadcasted directly from models that include this module (this is automatically done for Active Records if ActiveJob is loaded). This makes it convenient to execute both synchronous and asynchronous updates, and render directly from callbacks in models or from controllers or jobs that act on those models. Here’s an example:
class Clearance < ApplicationRecord belongs_to :petitioner, class_name: "Contact" belongs_to :examiner, class_name: "User" after_create_commit :broadcast_later private def broadcast_later broadcast_prepend_later_to examiner.identity, :clearances end end
This is an example from HEY, and the clearance is the model that drives the screener, which gives users the power to deny first-time senders (petitioners) access to their attention (as the examiner). When a new clearance is created upon receipt of an email from a first-time sender, that’ll trigger the call to broadcast_later, which in turn invokes broadcast_prepend_later_to.
That method enqueues a Turbo::Streams::ActionBroadcastJob for the prepend, which will render the partial for clearance (it knows which by calling Clearance#to_partial_path, which in this case returns clearances/_clearance.html.erb), send that to all users that have subscribed to updates (using turbo_stream_from(examiner.identity, :clearances) in a view) using the Turbo::StreamsChannel under the stream name derived from [ examiner.identity, :clearances ], and finally prepend the result of that partial rendering to the target identified with the dom id “clearances” (which is derived by default from the plural model name of the model, but can be overwritten).
You can also choose to render html instead of a partial inside of a broadcast you do this by passing the html: option to any broadcast method that accepts the **rendering argument. Example:
class Message < ApplicationRecord belongs_to :user after_create_commit :update_message_count private def update_message_count broadcast_update_to(user, :messages, target: "message-count", html: "<p> #{user.messages.count} </p>") end end
If you want to render a template instead of a partial, e.g. (‘messages/index’ or ‘messages/show’), you can use the template: option. Again, only to any broadcast method that accepts the +**rendering+ argument. Example:
class Message < ApplicationRecord belongs_to :user after_create_commit :update_message private def update_message broadcast_replace_to(user, :message, target: "message", template: "messages/show", locals: { message: self }) end end
If you want to render a renderable object you can use the renderable: option.
class Message < ApplicationRecord belongs_to :user after_create_commit :update_message private def update_message broadcast_replace_to(user, :message, target: "message", renderable: MessageComponent.new) end end
There are seven basic actions you can broadcast: after, append, before, prepend, remove, replace, and update. As a rule, you should use the _later versions of everything except for remove when broadcasting within a real-time path, like a controller or model, since all those updates require a rendering step, which can slow down execution. You don’t need to do this for remove, since only the dom id for the model is used.
In addition to the seven basic actions, you can also use broadcast_render, broadcast_render_to broadcast_render_later, and broadcast_render_later_to to render a turbo stream template with multiple actions.
Page refreshes
You can broadcast “page refresh” stream actions. This will make subscribed clients reload the page. For pages that configure morphing and scroll preservation, this will translate into smooth updates when it only updates the content that changed.
This approach is an alternative to fine-grained stream actions targeting specific DOM elements. It offers good fidelity with a much simpler programming model. As a tradeoff, the fidelity you can reach is often not as high as with targeted stream actions since it renders the entire page again.
The broadcasts_refreshes class method configures the model to broadcast a “page refresh” on creates, updates, and destroys to a stream name derived at runtime by the stream symbol invocation. Examples
class Board < ApplicationRecord broadcasts_refreshes end
In this example, when a board is created, updated, or destroyed, a Turbo Stream for a page refresh will be broadcasted to all clients subscribed to the “boards” stream.
This works great in hierarchical structures, where the child record touches parent records automatically to invalidate the cache:
class Column < ApplicationRecord belongs_to :board, touch: true # +Board+ will trigger a page refresh on column changes end
You can also specify the streamable declaratively by passing a symbol to the broadcasts_refreshes_to method:
class Column < ApplicationRecord belongs_to :board broadcasts_refreshes_to :board end
For more granular control, you can also broadcast a “page refresh” to a stream name derived from the passed streamables by using the instance-level methods broadcast_refresh_to or broadcast_refresh_later_to. These methods are particularly useful when you want to trigger a page refresh for more specific scenarios. Example:
class Clearance < ApplicationRecord belongs_to :petitioner, class_name: "Contact" belongs_to :examiner, class_name: "User" after_create_commit :broadcast_refresh_later private def broadcast_refresh_later broadcast_refresh_later_to examiner.identity, :clearances end end
In this example, a “page refresh” is broadcast to the stream named “identity:<identity-id>:clearances” after a new clearance is created. All clients subscribed to this stream will refresh the page to reflect the changes.
When broadcasting page refreshes, Turbo will automatically debounce multiple calls in a row to only broadcast the last one. This is meant for scenarios where you process records in mass. Because of the nature of such signals, it makes no sense to broadcast them repeatedly and individually.
Suppressing broadcasts
Sometimes, you need to disable broadcasts in certain scenarios. You can use .suppressing_turbo_broadcasts to create execution contexts where broadcasts are disabled:
class Message < ApplicationRecord after_create_commit :update_message private def update_message broadcast_replace_to(user, :message, target: "message", renderable: MessageComponent.new) end end Message.suppressing_turbo_broadcasts do Message.create!(board: board) # This won't broadcast the replace action end
Namespace
Modules
Extends
Methods (defined here)
- # broadcast_action
- # broadcast_action_later
- # broadcast_action_later_to
- # broadcast_action_to
- # broadcast_after_to
- # broadcast_append
- # broadcast_append_later
- # broadcast_append_later_to
- # broadcast_append_to
- # broadcast_before_to
- # broadcast_prepend
- # broadcast_prepend_later
- # broadcast_prepend_later_to
- # broadcast_prepend_to
- # broadcast_refresh
- # broadcast_refresh_later
- # broadcast_refresh_later_to
- # broadcast_refresh_to
- # broadcast_remove
- # broadcast_remove_to
- # broadcast_render
- # broadcast_render_later
- # broadcast_render_later_to
- # broadcast_render_to
- # broadcast_replace
- # broadcast_replace_later
- # broadcast_replace_later_to
- # broadcast_replace_to
- # broadcast_update
- # broadcast_update_later
- # broadcast_update_later_to
- # broadcast_update_to