We are working on transitioning a JS-heavy filtered list to Turbo Frames + Streams, and something we've run into seems like it might be a bug in Turbo.
We have a DealsController#index action that is one of the primary parts of our application, with a link in our main navigation to it like this:
<a href="/deals">Deals</a>
We've got Turbo Drive set up for the application, so with no introduction of Frames/Streams, this works perfectly, it updates the <body> through Drive as expected. Then we started introducing <turbo-frame>s to support things like infinite scrolling of "deals", with our index.html.erb looking something like this:
<%= turbo_frame_tag 'deals', target: '_top' do %>
<%= render @deals %>
<% end %>
<%= turbo_frame_tag 'deals-next-page', src: url_for(page: @page + 1), loading: 'lazy' %>
And an index.turbo_stream.erb that looks something like this:
<%= turbo_stream.append 'deals' do %>
<%= render partial: @deals, formats: %i[html] %>
<% end %>
<%= turbo_stream.replace 'deals-next-page' do %>
<%= turbo_frame_tag 'deals-next-page', src: url_for(page: @page + 1), loading: 'lazy' %>
<% end %>
However, when we introduce index.turbo_stream.erb, our navigation link (which is outside of any <turbo-frame> and should behave just as a simple Drive request) no longer works as expected. Instead of getting the full HTML response from the server and replacing the <body>, it receives index.turbo_stream.erb, which makes for all sorts of weird issues when clicking that navigation link from other pages (i.e. from our home page, where there is no <turbo-frame id: 'deals'> element on the page).
After looking into this a bit more, I'm pretty sure it's because Turbo Drive is including the Accept: text/vnd.turbo-stream.html header with all of its requests, which is causing my controller to respond with that format if it's available.
When clicking a link (or submitting a form) inside of a <turbo-frame> (without a target='_top'), that makes perfect sense to me, but I'm surprised it does this when clicking a link anywhere else on the page. In that case, I'd expect Turbo Drive to do its thing, and simply fetch the standard HTML response from the server, without the text/vnd.turbo-stream.html content type included in the Accept header.
Am I misunderstanding something basic about Turbo, or is this something that should be fixed?
We are working on transitioning a JS-heavy filtered list to Turbo Frames + Streams, and something we've run into seems like it might be a bug in Turbo.
We have a
DealsController#indexaction that is one of the primary parts of our application, with a link in our main navigation to it like this:We've got Turbo Drive set up for the application, so with no introduction of Frames/Streams, this works perfectly, it updates the
<body>through Drive as expected. Then we started introducing<turbo-frame>s to support things like infinite scrolling of "deals", with ourindex.html.erblooking something like this:And an
index.turbo_stream.erbthat looks something like this:However, when we introduce
index.turbo_stream.erb, our navigation link (which is outside of any<turbo-frame>and should behave just as a simple Drive request) no longer works as expected. Instead of getting the full HTML response from the server and replacing the<body>, it receivesindex.turbo_stream.erb, which makes for all sorts of weird issues when clicking that navigation link from other pages (i.e. from our home page, where there is no<turbo-frame id: 'deals'>element on the page).After looking into this a bit more, I'm pretty sure it's because Turbo Drive is including the
Accept: text/vnd.turbo-stream.htmlheader with all of its requests, which is causing my controller to respond with that format if it's available.When clicking a link (or submitting a form) inside of a
<turbo-frame>(without atarget='_top'), that makes perfect sense to me, but I'm surprised it does this when clicking a link anywhere else on the page. In that case, I'd expect Turbo Drive to do its thing, and simply fetch the standard HTML response from the server, without thetext/vnd.turbo-stream.htmlcontent type included in theAcceptheader.Am I misunderstanding something basic about Turbo, or is this something that should be fixed?