Turbo stream response to replace 2 elements only half working

Hello, I’m having some trouble with a turbo stream response. I want to replace two related elements on a page in a turbo stream response. The first element is a form_with model containing a checkbox that submits on change and the second is a form created with the button_to tag. My turbo_stream.erb file looks essentially like:

<%= turbo_stream.replace "toggle_id_#{@model.id}", partial: "partial_path",
locals: {model: @model} %>

<%= turbo_stream.replace "button_id_#{@model.id}", partial: "other_partial_path",
locals: {model @model} %>

So, the exact same handling for each element.

Everything works as expected when the toggle is clicked. The turbo_stream.erb file is rendered and in turn both partials are rendered, replacing both the toggle and the button_to form. However, if the button_to form is submitted, only the button_to form is replaced but not the toggle. The logs report the same renderings as when the toggle has been clicked. I can get them both to update if I override turbo for the button_to form, but I’d prefer not to and also I’d like to know what is going wrong.

Any ideas are appreciated.

Update: If I replace the nearest ancestor html element that contains both forms instead of each form separately, it works as expected. Still would love to know if anyone has any thoughts about why replacing them separately results in the strange behavior of only partly working.

Impossible to say based on the code you provided (I assume it’s vague on purpose), but are these two forms (the toggle and the button_to) handled by different controller actions? If so, you need to write a separate turbo_stream for each even though the end result, from the users’ standpoint, is the same.

As it currently stands, the toggle form submission is handled by the turbo_stream you have in place (update action?) while the button_to just changes its own frame.

If this is not the case, providing more code would help figure out what else may be going on.

Hi! Thanks for your reply. It’s not my project so I don’t know how much to share.

Both forms update the same boolean database column but are accessed through different parts of the page (the button appears in a drop down menu).

The controller actions look like:

def false_update 
      ....
      @model.update_to_false
      respond_to do |format|
        format.html { redirect_to root_path }
        format.turbo_stream { render "the_turbo_stream_path" }
      end
      ...
  end

  def true_update
    ...
    @model.update_to_true
    respond_to do |format|
      format.html { redirect_to root_path }
      format.turbo_stream { render "the_turbo_stream_path" }
    end
    ...
  end

  def toggle_update
    if @model.attribute?
      false_update
    else
      true_update
    end
  end

And then the button is rendered conditionally to go to one of false_update or true_update.

Since they already had the true and false update actions and wanted to add a toggling action, I thought I could set it up this way. But maybe not?

A side note. Using multiple controller actions to update single model attributes is usually considered poor form. A single update action can handle both your true_update/false_update actions and more closely follow the Rails REST/CRUD paradigm.

Oh duh. I’m not sure why I didn’t see that. Thanks.