-
Notifications
You must be signed in to change notification settings - Fork 437
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
HTTP 303 Redirects with anchor not respected #211
Comments
We have run into what seems to be this exact same issue, but with We could reproduce by configuring a link + anchor without a trailing <a href="../path#anchor">FAIL</a> Server responds with a The final expected and actual URL in the browser would be: // Expected
https://example.com/path/#anchor
// Actual
https://example.com/path/ If the tailing <a href="../path/#anchor">PASS</a> We understand that including a trailing |
I can confirm that this is an issue and I find it quite an unexpected behavior and would love to use my anchors. redirect_to '.../posts/433545#comment_221760128', status: :see_other
# gets redirected to /posts/433545
redirect_to '.../posts/433545/#comment_221760128', status: :see_other
# gets redirected to /posts/433545/ In both cases the anchor is lost. Using 301, 302, 303 makes no difference. Any ideas how to fix this? |
I believe this issue occurs for parameters as well. When I redirect with params in the same controller, the params are lost. If I redirect to a different controller, then the params are kept. Very strange! |
I'm seeing this behavior when performing any type of redirect after a successful form submission and the problem goes away if I disable Turbo. I'm also not using Rails so this is isolated to the JS library itself. I'm using beta 7 and I'm also not using frames or streams here. This is a basic full blown HTTP redirect. Reproduceable steps:
It's worth pointing out params are kept in tact in either case. I'm only losing the anchor with Turbo. |
I'm not sure how this can be fixed. As discussed in #257 (comment):
This means that the browser itself strips the anchor from the redirection URL, before it opaquely fetches the anchorless URL and hands the result to Turbo. There isn't a way for Turbo to excise the I think this is the relevant fetch issue: whatwg/fetch#1167 |
While it may not be possible to fix this, at a minimum it would be helpful if Rails were to emit a log message whenever a redirect with an anchor response is produced in response to a request that is being processed as TURBO_STREAM indicating that the anchor will effectively be ignored, and perhaps suggesting Unfortunately, looking at the current code, architecturally this is awkward.
Ideally, this would be a part of the hotwired turbo-rails gem, but as near as I can tell, absolutely none of server side logic which produces the redirect response goes through any code that is included in this gem. Perhaps turbo-rails could add some middleware to the processing, but that seems like a heavyweight solution that would penalize all applications in order to handle this one edge case. If my humble ramblings above spark any sort of ideas on how this situation can be improved, I'll be glad to develop or contribute a pull request to address this. |
Could also just start by adding the caveat to the docs. Explain why it isn't possible to fix. |
I'm also running into this issue for a Stripe redirection link, as described in the duplicate ticket at #565. I've asked Stripe to consider changing their anchor to an URL param, but I have no idea if that will actually happen in any meaningful amount of time, if at all. I'm not sure how "edge" of a case this is given the pervasiveness of Stripe, and the criticality of payments for most production web applications. |
Ok, I did a lot more work investigating and I think I narrowed it down to a CORS policy. If the URL with an anchor tag emits the header For example, this won't redirect to the anchor: redirect_to "https://checkout.stripe.com/c/pay/cs_test_a1N9yeht6Z860VIwhoLHpJYVRo3Hlr9tIhd1foVLhTofesLGenoGVRcZdJ#anchor", allow_other_host: true Because it returns a 200 OK with a But this will work: redirect_to "https://checkout.stripe.com/#anchor", allow_other_host: true Because the URL does not emit a CORS header and the connection gets canceled. |
Not sure if this is related but I have the same problem with a simple <form action="/some/page#anchor" method="get">
...
</form> Submitting the form (with Turbo enabled) actually sends a request to The server simply responds with status Is this the same problem or something different? |
For those trying to execute the Stripe redirect, as mentioned by @rubys, using (In this example, we're using a PaymentMethodsController)
Works well for me. |
hotwired/turbo#211 could not redirect with anchor tag
I believe we are hitting this in a rails This is a fresh rails 7.1.1 application with a single controller serving an index and redirect endpoint. The summary for what works (and what doesn't): ![]() Although the anchor not showing is an issue (users can't copy & paste the page at the right spot), our main problem is actually that Turbo doesn't scroll to the element. GET, despite not updating the URL does indeed scroll correctly. Thoughts if this PATCH / no scroll issue all part of the same problem or a different issue? For background, we're using a link to with a turbo PATCH to process end user notifications (they click, notification is marked as read and then they are redirected to the relevant comment - although now they are redirected to the top of the page). UPDATED: I updated the repo with more test options. One really weird finding an anchor scenario on the link dominating that of the response from the server. UPDATED: I created a blog post to explain the issue further. In writing it, it seems really odd to me that this is an issue that isn't receiving attention. Are anchors not cool any more!? UPDATED: It isn't pretty, but I created another blog post with our first stab at a workaround. Not gonna lie, it includes a timer :( However, it does look to work with get / post requests with redirects using anchors and scrolls to the correct location. This is can all be see via https://github.com/harled/turbo-anchor-issue/tree/turbo-anchors |
Note an unexpected issue: URL anchors aren't handled by Turbo redirects (see hotwired/turbo#211), so Turbo has to be skipped. which is too bad. TODO: find a solution to scroll to the anchor. (Plus find a way for the edit action to figure out _which anchor_ to use.)
Hi ! Im'm using Turbo UX with Symfony 7, I can confirm anchors don't work.
redirects me to "/gerer" (with or without "/" before "#") |
Ran into this again. Given this code: =link_to "Upgrade now →", account_payment_path(@account), "data-turbo-method": "post", class: "btn btn-primary is-medium" Here's the work around I went with this time: = form_tag account_payment_path(@account), method: :post, "data-turbo": false do
= button_tag "Upgrade now →", class: "btn btn-primary btn-lg w-full" |
Ran into the same issue, also with Stripe Checkout. This seems like a pretty substantial bug. Is there a workaround that lets us specify something in the controller action, rather than having to remember to disable turbo for each link that points to this action? |
I discovered today that some of my links have this issue. It seems like a hard thing to fix properly, but does anyone know a workaround? Thanks in advance |
I was implementing a notification sidebar and I got into this problem. In my implementation some notifications have an anchor in the redirect url so once the browser loads it can scroll to the correct element. Here is my workaround for anyone that might find it useful. I had to change the status code from the class RecipientNotificationsController < ApplicationController
def show
@recipient_notification.read!
# Workaround this sends status :ok because of opaque redirect in fetch API
redirect_to notification_origin_path(anchor: ...), status: :ok
end
end Then on the notification card with the link I added a stimulus controller that handles the anchor link <%= turbo_frame_tag dom_id(recipient_notification) do %>
<%= link_to recipient_notification_path(recipient_notification), data: {
turbo_frame: '_top',
controller: 'redirect-preserving-url-anchor',
action: 'redirect-preserving-url-anchor#redirect',
'turbo-prefetch': false
}, class: 'notification-link' do %>
<% # ... %>
<% end %>
<% end %> And here is the Stimulus contorller import { Turbo } from '@hotwired/turbo-rails';
import { get } from '@rails/request.js';
import ApplicationController from './application_controller';
export default class extends ApplicationController {
async redirect(event) {
event.preventDefault();
const response = await get(this.element.href);
if (response.ok) {
const location = response.headers.get('Location');
Turbo.visit(location, { action: 'replace' });
}
}
} |
Here is another temporary solution we are using. Instead of the server to return a 302 redirect, it can return a 200 status code with a turbo stream redirect to respond to turbo. Example Rails Code to redirect to expected_path(resource, anchor: 'myanchor') after form submission
Response body then would be |
@marckohlbrugge a workaround an LLM1 gave was to add this to application.js document.addEventListener("turbo:load", function() {
const params = new URLSearchParams(window.location.search);
if (params.get('scroll_to')) {
const element = document.getElementById(params.get('scroll_to'));
if (element) element.scrollIntoView();
}
}); then instead of redirect_to your_path(anchor: "your-id") use redirect_to your_path(scroll_to: "your-id") I've only tried this in one place, but it seemed to work. Hope it may help. 1. Treat with appropriate caution |
Way prettier than what we did as a workaround! We continue to struggle with educating (new and old) developers on this whole problem of anchors with turbo. The two bad options continue to be:
🤦 🤦 🤦 p.s. couldn't help but smile clicking the notification link for this email and seeing the beautiful anchor in it that scrolled perfectly! |
@stevecondylios (cc @krsyoung) I'm using this modified version of your snippet, which does not require to replace document.addEventListener("turbo:load", () => {
const hash = window.location.hash
if (hash) {
const element = document.getElementById(hash.slice(1))
if (element) element.scrollIntoView()
}
}) We are overriding the browser's default behavior, so this is still to be considered a workaround. |
Steps to Reproduce:
Location: /path#anchor
).Observed Behavior:
/path
instead of/path#anchor
)Expected Behavior
Workaround
Wild Guess Hypothesis
I suspect that the subsequent redirection fetch (from Turbo) strips the anchor tag from the underlying HTTP request (as expected), but when the page is re-hydrated, the address bar URL (pushstate) is not updated to reflect the original anchor.
The text was updated successfully, but these errors were encountered: