-
Notifications
You must be signed in to change notification settings - Fork 433
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
Preserve URL hash when response is redirected #849
Conversation
This pull request adds test coverage to demonstrate a limitation in Turbo's support for redirecting to a URL with a [hash][] value. Currently, redirecting to a URL with a hash (for example, `/src/tests/fixtures/one.html#element-id`) omits the hash (`#element-id`) when navigating to the final destination. According to the [fetch specification][], redirects should preserve URL fragments during redirection. [hash]: https://developer.mozilla.org/en-US/docs/Web/API/URL/hash [fetch specification]: https://fetch.spec.whatwg.org/#http-redirect-fetch
@manuelpuyol thank you for opening this! When I opened #765, I was trying to reproduce the behavior for something like this from a Rails controller: class PostsController < ApplicationController
def create
@post = Post.create!(post_params)
redirect_to posts_url(anchor: helpers.dom_id(@post))
end
end Note the anchor: keyword argument. The idea is that it'd redirect to I might be misunderstanding the implementation changes, but is the code reading the |
@seanpdoyle Interesting, I thought that the test was supposed to showcase #825 since they are really similar. Here I want to emulate the browser's redirect behavior when the initial URL has a hash. When redirected, the browser will reapply the hash to the new URL: Screen.Recording.2023-01-17.at.2.12.16.PM.movBut when Turbo was driving the request, the hash was not preserved: Screen.Recording.2023-01-17.at.2.13.18.PM.movSo yeah, I'm reading the |
|
||
const location = fetchResponse.location | ||
if (redirected) { | ||
location.hash = formSubmission.fetchRequest.location.hash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a form submission redirects to a URL containing a hash
-- description from #825
In my understanding, the "redirects to a URL" part is describing a URL decided on the server-side. This implementation seems like it's reading the formSubmission.fetchRequest.location.hash
value from a URL decided on the client-side.
To make it concrete, I was hoping to highlight the fact that Turbo cannot access the anchor:
value from redirect_to posts_url(anchor: helpers.dom_id(@post))
, and not the #a-hash
value from the [action]
attribute from an element like <form action="/posts#a-hash"></form>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With that being said, let's fix both!
I think the server-side value will be inaccessible for the same reasons that headers in intermediate redirect responses are inaccessible (see the "Making it work with Turbo Frames and redirects" heading in #257 (comment)).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any idea how we could make Turbo know about hashes coming from the server? It looks like we have two bugs here and this implementation fixes the one I mentioned
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seanpdoyle looks like there's no way to get the hash coming from the server since fetch responses are always stripped node-fetch/node-fetch#211 (comment)
Would it be ok to move forward with the client fix first?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just found whatwg/fetch#1167 as a proposal to expose the fragment for the response url. I mentioned the Turbo tickets I found about it as use cases for that proposal.
Based tests from #765
When a response is redirected, the initial request's hash param is lost. This happens because the
response.location
that we use to initiate the visit redirect does not have a hash.I'm fixing this problem by setting the request's
hash
in the response.location object in case there was a redirect.