ruby-on-railshotwire-railsturboturbo-frameshotwire

Network response with nested turboframe linking to same page doing a full html request?


I have a nested turbo frame

My controller is something like

def landing_page
  @variable = params[:variable].present? ? params[:variable] : "hello"
end

The view for my landing page is:

<%= turbo_frame_tag "outer" do %>
  <div><%= @variable %></div>
  <%= turbo_frame_tag "inner" do %>
    <div><%= @variable %></div>
    <%= link_to "link to same landing page", landing_page_path(variable: "World") %>
  <% end %>
<% end %>

On initial page render:

  1. there is no params[:variable], so the value of @variable is "hello"
  2. on the page itself, both variables successfully output the text of "hello"

When I click on the link:

  1. params[:variable] exists, therefore the value of @variable on the incoming turbo frame is "world"
  2. It modifies variable in the "inner" turbo_frame, but does not modify the variable in the "outer" turbo_frame.

This is actually the functionality I want (I am successfully able to modify the inner frame, but not the outer one). However, when looking at the network tab, this appears to be making a full HTML page request, even though it's only modifying the inner frame.

I would expect the network request to be something like:

<turbo-frame id="inner">
  <div>World</div>
  <a href="/rooms?variable=World">link to same landing page</a>
</turbo-frame>

instead, the network tab is showing that I'm receiving the entire html of

<html>
  <head>
  </head>
  <body>
    <turbo-frame id="outer">
      <div>World</div>
      <turbo-frame id="inner">
        <div>World</div>
        <a href="/rooms?variable=World">link to same landing page</a>
      </turbo-frame>
    </turbo-frame>
  </body>
</html>

The examples I've seen in the rails tutorial always seem to be predicated on the idea of going from one page to another page. Unfortunately, in my exact use case, I'm using a multistep form gem called wicked wizard and it doesn't seem like I can use turbostreams for this, and moving the inner frame outside of the outer frame isn't an option


Solution

  • That's how it works. The "full" page response you are seeing is response rendering in a turbo frame layout.

    When you send request to your landing page url, controller renders a landing_page.html.erb template from landing_page action, where you have two turbo frames. That renders into a one big string and is sent back as a response.

    On the front end, turbo parses the response and only updates the relevant frame, the rest is discarded. That's why TurboFrame is simpler to use. You don't need a partial or another response format.

    The response you're thinking of is when you render a turbo_stream, but that's because you have to have a turbo_stream response and you have to specifically render <turbo-stream> tag:

    render turbo_stream: turbo_stream.update("tag_id", "new content")
    # which only renders a turbo-stream tag
    <turbo-stream action="update" target="tag_id"><template>new content</template></turbo-stream>
    

    Sure, you can also have a partial and render just the frame you need if you really want to. But I don't see why you wouldn't be able to use turbo stream or turbo frame or both:

    <%= tag.div id: :current_step %>
    
    <%= turbo_frame_tag "wizard" do %>
      <% case params[:step].presence || "one" %>
      <% when "one" %>
        <%= turbo_stream.update("current_step", "Step one") %>
        <%= link_to "next", landing_page_path(step: "two") %>
      <% when "two" %>
        <%= turbo_stream.update("current_step", "Step two") %>
        <%= link_to "next", landing_page_path(step: "complete") %>
      <% when "complete" %>
        <%= turbo_stream.update("current_step", "Step three") %>
        <%= link_to "next", landing_page_path %>
      <% end %>
    <% end %>