`turbo_frame_tag` appending response to the end of the body instead of replacing

hey everyone :wave:

I’m a bit confused with something: I have a create action that was rendering a partial upon a successful response. something like this:

<%= turbo_frame_tag 'new-message-form' do %>
  <%= form_tag messages_path, data: { action: 'turbo:submit-start->loader#started turbo:submit-end->loader#finished ' } do %>
<% end %>
def create
  message.encrypt!(password: params[:password])
  render partial: "messages/tada", locals: { message: }
end

and the partial had this content:

<%= turbo_frame_tag "new-message-form" do %>
  <div data-controller="...
<% end %> 

and this is/was working fine, the whole frame gets replaced by the contents of the partial.
I decided to get rid of this partial and moved the content of this partial to create.turbo_stream.erb but I noticed that upon a successful request, the content of the create.turbo_stream.erb was getting appended to end of the body.

I fixed by using <%= turbo_stream.replace "new-message-form" do %> in the file but now I’m confused and I have a question: why does the partial replaces the contents just fine while using the create.turbo_stream.erb way forces me to explicit tells turbo what to replace? that goes against every example I see on the web, where Turbo is smart enough to match the response’s turbo frame tag id with the one in the form and automatically replace it.

I do not have any special configuration or something in my application.js file too

Ok, so I managed to get it to work by renaming create.turbo_stream.erb to create.html.erb but I thought that since it is a turbo stream request, it should have a turbo_stream template file. I guess I misunderstood this part then. When should you use turbo_stream and html template files? I’m thinking that the rule of thumb is something like whenever you want to update multiple things in the page, you use a turbo_stream template file with different actions and you just go with html when you want to simply replace/update a single frame. does that makes sense?

I’m thinking that the rule of thumb is something like whenever you want to update multiple things in the page, you use a turbo_stream template file with different actions and you just go with html when you want to simply replace/update a single frame. does that makes sense?

@luizkowalski I think you’ve basically got this thinking right. You may also have gotten confused about the difference between turbo frames and turbo streams. With turbo frames, when you render the create.html.erb template with the turbo_frame_tag “new-message-form” element, Turbo will look for the element with the id of ”new-message-form” in the DOM and replace it with the contents of the turbo_frame_tag in the HTTP response.

With turbo streams, you could use a create.turbo_stream.erb template, but in that case you would want to wrap your HTML fragments inside of a <turbo-stream> element that specifies the action, maybe something like:

<turbo-stream action=“replace” target=“new-message-form”>
  <div data-controller="...
</turbo-stream>

And yes, you could include multiple <turbo-stream> elements in this template with different actions that update different parts of the page. Given your specific example here, there wouldn’t necessarily be an advantage to using turbo streams here since you seem to be only updating that one element on the page. If you needed to update multiple elements with different actions, then that’s when I would reach for turbo streams.

Another way to use streams here would be to leave your original partial where it was in ”messages/tada”, and instead of rendering the partial at the end of the create action or rendering a template, you could respond with a turbo_stream response like:

def create
  message.encrypt!(password: params[:password])
  render turbo_stream: turbo_stream.replace(“new-message-form”, partial: "messages/tada", locals: { message: … })
end

Then you wouldn’t need either a create.html.erb or a create.turbo_stream.erb template, and this would keep the partial reusable elsewhere. Again, I’d probably still reach for a regular turbo frame first unless I had a good reason to reach for streams, such as multiple elements needing to be updated on the page.

Hope that helps!

1 Like

that clears everything! thanks a lot, Thomas!

1 Like