-
Notifications
You must be signed in to change notification settings - Fork 435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Break out of turbo frame loses flash #897
Comments
Hi @gap777, the page being fetched twice is part of how It has to make that second request to do the reload. That's partly because it's the mechanism for doing a full-page (not JS fetch) load, which is what that meta tag specifies is required. But it's also because the initial response may have omitted some content that wasn't needed in a frame context, but would be needed for the full page. Turbo Rails will do this by default -- it'll use a minimal layout, rather than the application layout, when responding to a frame request. So unfortunately if you render the flash message in that first response then it will get lost, as you say. The simplest solution I can think of is to render the flash content in your application layout. Since that's not used when responding to the frame request, it should be present on the full page load. That should avoid this problem in general (and is how I normally have things set up anyway). If having the flash in the layout doesn't suit, and you want to fix this for a specific page, you could potentially persist the flash explicitly between those two requests, by doing something like this in the controller action: flash.keep if turbo_frame_request? Or you could make rendering the flash conditional in some other way; whatever way best suits your app. I've just quickly tested those two approaches and both seem to do the trick. But let me know if it doesn't work out for you. |
@kevinmcconnell Thank you for such a quick response! Actually, my flash content is a part of my layout: / layouts/application.html.slim
doctype html
html lang='en' data-theme-mode='light'
= render 'core_ui/layouts/head'
body.app-wrapper
= render 'core_ui/shared/modal'
= render 'core_ui/shared/confirm'
/ Side Navigation
= render 'core_ui/layouts/side_nav'
.app__main
= render 'core_ui/shared/flash'
.page__header
= render 'core_ui/layouts/page_header'
.page__subheader
= yield(:subheader)
.page__content
.page__content-area
= content_for?(:content) ? yield(:content) : yield It seems like you're surprised that the application layout is being included in the turbo frame response. # controller logic, resulting in determining an error state ....
format.html do
redirect_to that_other_path, status: :see_other, alert: @error_message
end Are you suggesting that the subsequent GET from redirect does not include application layout? |
Ah yes, sorry, I was speaking specifically about how it works with Turbo Rails. I should have been clearer about that! Turbo Rails will override the layout when the request is coming from inside a turbo frame. Such requests have a But if you're using Turbo outside of Turbo Rails (or if you are using Turbo Rails but are overriding the layout), that's not going to happen. I don't know how your app is set up. But you always have the option of doing something like this yourself, if it suits your case. You could consider skipping the flash portion when that This is the part where Turbo Rails does this, which might explain this better than I have :) I think what it boils down to, in either case, is you either need to not render your flash on that first GET, or you need to use a |
Just encountered this issue too. I'm using the workaround you suggested here #863 (comment) and using I mentioned a particular use case here #867 (comment) where this also applies. Wondering if the solution is rather finding a way to break out of the frame from the controller. Allowing the flash to work as before in this case. |
@kevinmcconnell @davidalejandroaguilar Huh.... I'm using Rails 7, and my package.json includes
Maybe the next question is, "Why is my application layout being used? (given the logic https://github.com/hotwired/turbo-rails/blob/main/app/controllers/turbo/frames/frame_request.rb#L24". |
Ok, I think I have an idea... My controller has a I tried replacing my controller This causes the So... how do I break out of a turbo frame and redirect w/ a flash (alert)? |
I'll allow that this is all new to me, so maybe I'm missing something... but the solution proposed here (https://stackoverflow.com/a/75750578/438205) of a custom turbo action seems exactly what I want. If Turbo Rails has an answer for this scenario, I'd prefer to use the canonical one... but I can accept a custom one, given the custom one is extending things in "blessed" ways. ;-) |
@gap777 yes, your The way this works with the Turbo Rails version is that it has a That means your page's view can include the Turbo Rails provides a helper for this: if you're using its layout (or you have a <% turbo_page_requires_reload %> Or if you want to do it without the helper, a block like this should work: <% content_for :head do %>
<meta name="turbo-visit-control" content="reload">
<% end %> In your situation, that is probably what I'd do: make sure the layout I'm using for frame content has a But a Turbo Streams action is an interesting idea too! There's certainly many different ways to approach it :) |
@kevinmcconnell Thanks for explaining things so patiently. I tried your recommended approach, and am able to do what I want. My scenario is specific to wanting to break out of a turbo frame with a redirect to another page (eg, in an error scenario). I don't want to unconditionally include that So I've put a conditional guard around the I'd really like this "guarded turbo_page_requires_reload" expression on every page, so that any page can break out of a turbo frame and redirect to wherever it wants... but then I have to litter every page with this expression. I can't include it in the layout, b/c of course, layouts aren't used from within the context of a turbo frame request. So.. you've helped me in the immediate problem. But the larger strategic pattern seems be escaping me. |
Okay here we go! so for everyone and anyone that been through all of this like me this is how you could redirecting and rendering notice from a turbo frame
|
@laptopmutia Unfortunately, that'd make the page where you add Example:
If we added |
A better workaround is adding But it's only needed because of the turbo:frame-missing workaround that causes 2 requests when the frame is missing and losing the flash in the process. For me, this is appropriate: class ApplicationController < ActionController::Base
before_action :keep_flash_if_turbo_frame_request
def keep_flash_if_turbo_frame_request
flash.keep if turbo_frame_request?
end
end The PR for breaking out of a frame from the server internally handles the missing flash, so that really is the best solution. |
Hi,
I'm trying to use the recent changes to allow server-side decision to break out of a turbo frame. Here's my sequence of activity:
The issue I'm reporting is the server logs show the redirected-to page being fetched twice (steps 3 and 4), and the flash message (included in the response to 3) is discarded and not included with step 4.
Am I doing something wrong?
Is this a bug?
The text was updated successfully, but these errors were encountered: