Hotwire turbo_stream_from single update bug

Recently, we encountered a bug with some Stimulus code. We were trying to stream updates for a small partial and found that data only refreshed on the first update.

Here’s the code we were using:

Template:

1
2
3
4
<%= turbo_stream_from "revenue" %>
<div id="revenue">
  <%= render partial: 'metrics/revenue', locals: { revenue: @revenue } %>
</div>

Model:

1
2
3
4
5
6
7
class Sale < ApplicationRecord
  after_commit -> { broadcast_replace_to "revenue", partial: "metrics/revenue", locals: { revenue: Sale.total }, target: "revenue" }

  def self.total
    pluck(:amount).sum
  end
end

broadcast_replace_to is used to trigger the replace stream action. The documentation for Turbo actions is sparse but it’s reasonable to expect that this method replaces a DOM element with a new one. However, broadcast_replace_to only updates a DOM element once. This causes a strange bug where the first model update triggers a page re-render but subsequent updates do not.

In the end, we fixed the bug by switching to update. Here’s the new model code:

1
2
3
class Sale < ApplicationRecord
  after_commit -> { broadcast_update_to "revenue", partial: "metrics/revenue", locals: { revenue: Sale.total }, target: "revenue" }
end

Hopefully this will save you some debugging time!