Code snippets:
application.html.erb
:
<%= turbo_stream_from current_user, "counter" %>
<% if current_user%>
<%= render partial: "users/counter", locals: { user: current_user } %>
<% end %>
users/_counter.html.erb
:
<%= turbo_frame_tag "#{dom_id user}_counter" do %>
<span class="text-subtitle">counter:<%= user.counter %></span>
<% end %>
user.rb
:
include ActionView::RecordIdentifier
after_update_commit -> { broadcast_replace_to [self, "counter"],
partial: "users/counter",
locals: { user: self },
target: "#{dom_id(self)}_counter"
}
The first time the page is loaded or refreshed, it shows the correct counter value. Relevant HTML:
<turbo-frame id="user_1_counter">
<span class="text-subtitle">counter:19</span>
</turbo-frame>
Update counter via console:
irb(main):030:0> user.counter = 20
=> 20
user.save!
TRANSACTION (0.0ms) begin transaction
USELECT 1 AS one FROM "users" WHERE "users"."username" = ? AND "users"."id" != ? LIMIT ? [["username", "test 4"], ["id", 1], ["LIMIT", 1]]
User Update (0.6ms) UPDATE "users" SET "updated_at" = ?, "counter" = ? WHERE "users"."id" = ? [["updated_at", "2022-07-26 21:38:47.033843"], ["counter", 20], ["id", 1]]
TRANSACTION (0.4ms) commit transaction
Rendered users/_counter.html.erb (Duration: 0.0ms | Allocations: 8)
[ActionCable] Broadcasting to Z2lkOi8vY2x1Y2tjbHVjay9Vc2VyLzE:counter: "<turbo-stream action=\"replace\" target=\"user_1_counter\"><template><span class=\"text-subtitle\">counter:20</span></template></turbo-stream>"
=> true
HTML on the screen after this change is broadcast, shows the new counter value, but the turbo-frame
tag is gone:
<span class="text-subtitle">counter:20</span>
If I change the counter again in console, even though the broadcast gets sent, nothing changes on the webpage. And that makes sense since there is no element with matching target ID.
My question is, why is the <turbo-frame>
not being rendered after the first update?
Using the target ID on a regular HTML element and not using
turbo-frame
tag seemed to fix the issue.New
_counter.html.erb
: