4

I've got hotwire/turbo wired up correctly to do crud operations on a single model on one place of my page, but I'd like to update the same model at the same time in a different location on my page as well. I thought I could just set up two streams but it doesn't seem to work.

Specifying a target does work for create action depending on how I name the target, but not for update and destroy. This is what I think should work but doesn't:

----location 1 ("creatures" stream)----

<div id="creatures">
  <%= turbo_stream_from "creatures" %>
  <%= turbo_frame_tag "creatures" do %>
    <div>
      <% @creatures.each do |creature| %>
        <div>
          <%= render "creatures/creature", creature: creature %>
        </div>
      <% end %>
    </div>
  <% end %>
</div>

----location 2 ("creatures_main" stream)----

<%= turbo_stream_from "creatures_main" %>
<%= turbo_frame_tag "creatures_main" do %>
  <% @creatures.each do |creature| %>
    <div>
      <%= render "creatures/creature", creature: creature %>
    </div>
  <% end %>
<% end %>

---- common _creature.html.erb partial ----

<%= turbo_frame_tag dom_id(creature) do %>
  <%= link_to creature.name, "#" %>
<% end %>

---- creature.rb ----

class Creature < ApplicationRecord
  validates :name, presence: true

  after_create_commit {
    broadcast_append_to "creatures"
    broadcast_append_to "creatures_main"
    }
  after_update_commit {
    broadcast_replace_to "creatures"
    broadcast_replace_to "creatures_main"
    }
  after_destroy_commit {
    broadcast_remove_to "creatures"
    broadcast_remove_to "creatures_main"
    }

end

What happen when I have two calls in my model is that the create action puts the newly created creature in location 1 twice, only 1 of the two are updated,but both are destroyed correctly regardless of where on the page they are.

Vince W
  • 161
  • 2
  • 9

1 Answers1

3

creatures and creatures_main would be the stream name. What you're looking for is the target and partial to control where the stream would look to update your data, and which partial it would use to update.

You can try:

after_create_commit -> {
  # target here is the ID of the outer div, where data would be appended to
  broadcast_append_to "creatures", target: "creatures"`
  broadcast_append_to "creatures_main", target: "creatures_main"
}
after_update_commit {
  # target here is the ID of each of the creature div
  broadcast_replace_to "creatures", target: "creature_#{id}"
  broadcast_replace_to "creatures_main", target: "creature_main_#{id}"
}
after_destroy_commit {
  broadcast_remove_to "creatures"
  broadcast_remove_to "creatures_main"
}
<%= turbo_frame_tag "creature_#{creature.id}" do %>
  <%= link_to creature.name, "#" %>
<% end %>

<%= turbo_frame_tag "creature_main_#{creature.id}" do %>
  <%= link_to creature.name, "#" %>
<% end %>

Of course this means you might have to use 2 different partials if you have the turbo_frame_tag inside the partial. You can do so like this:

after_update_commit {
  # target here is the ID of each of the creature div
  broadcast_replace_to "creatures", target: "creature_#{id}", partial: "creatures/creature", locals: {creature: self}
  broadcast_replace_to "creatures_main", target: "creature_main_#{id}", partial: "creatures/creature_main", locals: {creature: self}
}

Btw, you should use the _later version of those methods. Also use render collection for easier reading.

Van Tran
  • 31
  • 2