Skip to content
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

Closed
wants to merge 6 commits into from
Closed

Preserve URL hash when response is redirected #849

wants to merge 6 commits into from

Conversation

manuelpuyol
Copy link
Contributor

@manuelpuyol manuelpuyol commented Jan 17, 2023

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.

seanpdoyle and others added 3 commits October 13, 2022 13:29
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
@seanpdoyle
Copy link
Contributor

seanpdoyle commented Jan 17, 2023

@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 /posts#post_1.

I might be misunderstanding the implementation changes, but is the code reading the .hash value from a URL that's known at request-time, or is it reading it as part of the response-time URL?

@manuelpuyol
Copy link
Contributor Author

@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.mov

But when Turbo was driving the request, the hash was not preserved:

Screen.Recording.2023-01-17.at.2.13.18.PM.mov

So yeah, I'm reading the hash from the initial request to pass it forward to redirects, since the response object will ignore it for some reason

@seanpdoyle
Copy link
Contributor

I'm sorry to confuse the point. Yes, the tests in #765 are meant to exercise the behavior described in #825.


const location = fetchResponse.location
if (redirected) {
location.hash = formSubmission.fetchRequest.location.hash
Copy link
Contributor

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>.

Copy link
Contributor

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)).

Copy link
Contributor Author

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

Copy link
Contributor Author

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?

Copy link

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.

@manuelpuyol manuelpuyol closed this by deleting the head repository Apr 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants