Rails 7广播turbo streams
Broadcasting your turbo streams as you want them in Rails 7
Hotwire has been around for a while now. If you got a chance to create an app powered by it yet, you must have realized how easy it is to create apps that feel like single-page applications. In this blog, we will see the lesser-discovered part of the ecosystem - broadcasting.
Turbo streams
Think of turbo streams as a set of changes to perform on your UI. You send these changes back to the UI as a response to an event, form submission, or whenever you feel like it. If you are new to this, I recommend going through the Turbo - The heart of Hotwire first.
Broadcasting?
If you are creating an application where you want changes in the UI to be reflected not just for the instance that requested it but for others (who're viewing the same page) too, then broadcasting is what you need.
Let's take a simple example of a notifications feature.
Image depicting change in notification icon
How would you make sure that if an event occurs, the notification icon updates for everyone? You can create a turbo stream that replaces the icon and send that turbo stream to everyone.
First, everyone has to listen to a WebSocket channel for incoming turbo streams. This is done using
第一步:监听WebSocket
第一步:监听WebSocket
<%= turbo_stream_from(:notifications) %>
where :notifications is just the name of the channel.
Second, you broadcast the update using the special broadcasting methods provided by the Turbo::Broadcastable concern.
第二步,通过Turbo::Broadcastable...广播需要更新的相关内容
第二步,通过Turbo::Broadcastable...广播需要更新的相关内容
broadcast_replace_to(:notifications, target: "icon", html: "<span class='icon'>notification_new</span>")
This method does two things
- Generates the turbo stream.
- Broadcasts the turbo stream to all subscribers of the notifications channel.
The broadcasted turbo stream looks something like this:
<turbo-stream action="replace" target="icon"> <span class='icon'>notification_new</span> </turbo-stream>
You can call this function in the controller or in the model after a callback like:
# app/models/Post.rb class Post < ApplicationRecord ... after_create_commit -> { broadcast_replace_to( :notifications, target: "icon", html: "<span class='icon'>notification_new</span>" ) } ... end
Once a post is created, the icon for all the users will be replaced with a new one indicating a new notification.
The ways of Broadcasting
So far, you have seen one type of broadcasting - replace. There are broadcasting functions for every type of turbo stream actions - broadcast_update_to, broadcast_append_to ... the entire list is here. Let's see some of the common hurdles that you might face while using them.
Multiple Turbo stream actions at once?
If you want to broadcast multiple turbo stream actions at once, you can put all of your actions in one *.turbo_stream.erb file and broadcast the file!
# app/views/notifications/_new.turbo_stream.erb <%= turbo_stream.replace "icon" do %> <span class='icon'>notification_new</span> <% end %> <%= turbo_stream.append "icon" do %> <span class="count"><%= count %></span> <% end %> # app/models/Post.rb class Post < ApplicationRecord ... after_create_commit -> { broadcast_render_to( :notifications, partial: "notifications/new" ) } ... end
Selective broadcasting?
If you want to multicast a turbo stream instead of broadcasting it, just make sure it reaches the right receivers. You can distinguish between your receivers by giving them their own channels.
For an example, different users are in different groups, and you want only the people inside the group to get the updates, how do you distinguish them from all the other users in the other groups?
<%= turbo_stream_from(@group) %>
This will create a unique channel for each group, and when you broadcast your updates,
# app/models/Post.rb class Post < ApplicationRecord belongs_to :group ... after_create_commit -> { broadcast_render_to( group, partial: "notifications/new" ) ... end
It will be broadcasted to only the required groups/channels.
Testing your broadcasts
Of course, you would want to make sure your broadcasts are going through the correct channels but how do you test that? With ActionCable test helpers.
test "notifications are sent to same group" do stream = @group target = "icon" assert_broadcast_on stream, turbo_stream_action_tag("replace", target: target, template: %(<span class='icon'>notification_new</span>)) do Post.create(title: 'A new post') end end
High response time!
If the broadcasting of your turbo stream is an expensive operation, just create a Turbo::Streams::BroadcastJob to broadcast later in a background job. This is done using broadcast_*_later_to methods.
# app/models/Post.rb class Post < ApplicationRecord belongs_to :group ... after_create_commit -> { broadcast_render_later_to( group, partial: "notifications/new" ) ... end
You can try these examples in the demonstration app here. That's all about broadcasting for now. Until next time.
https://blog.kiprosh.com/broadcasting-your-turbo-streams-as-you-want-them-in-rails-7/
https://github.com/imanpalsingh/broadcasting_sample
https://blog.kiprosh.com/tag/rails_7/
https://github.com/imanpalsingh/broadcasting_sample
https://blog.kiprosh.com/tag/rails_7/
阅读量: 1166
发布于:
修改于:
发布于:
修改于: