Running Rails 5.0.0beta3 + TurboLinks 5.x
When I post a form for "create", and the create action re-renders the "new" action, turbolinks is updating the URL to the POST url.
If the user then reloads the page, they end up with the index action rather than back at "new"...
Turbolinks doesn’t handle form submission. Please see Redirecting After a Form Submission in the documentation.
The redirection part isn't the problem, its when it doesn't redirect but instead does
render action: 'new'
because some error occurred..
Just to be clear,
Suppose I'm at a page /users/new
I fill out the form but omit a required field, and then click submit.
The url changes to /users but rails will render action:new
If you were to then refresh the page, you will then end up with the index action rather than the new action.
Similarly, if you are editing a user at /users/1/edit and click save, the URL would update to /users/1 and a refresh would get you the show action instead of the edit action.
I don't think this is a Turbolinks problem. You should see the same behavior in an app that doesn't use Turbolinks.
Your right - I think I might have misunderstood my issue..
Thanks,
Stephen
Same issue. URL change is intended behavior, but refresh with GET is not.
When turbolinks is not required in application.js; after refreshing a form with errors, a confirmation dialog appears which on confirming resends the form data to the server on the form action url again.

Whereas, when turbolinks is required, it refreshes the page (to the index action) without displaying a confirmation dialog.
This is not an intended behavior (as it seems like overriding the default Rails behavior in such a case).
@vishaltelangre seeing the same behavior and I do believe it is a bug. After the server renders errors resulting from a POST, browsers typically re-submit the POST on refresh. With turbolinks, the browser does a GET which in my case goes to a 404 (we don't have an index page for this resource). Is this intended behavior? If not, can we re-open this issue?
@vishaltelangre @lserman I have the same problem. I don't know whether this is an intended behavior.
Same here.
If I remove Turbolinks 5.0.1 from my Rails 5.0.0.1 app, everything works as expected (Hitting F5 triggers a browser warning before resubmitting the form via POST).
If Turbolinks is active (while not actually being used on form submits), this default behaviour breaks. When hitting F5, the browser issues a GET to the current URL.
+1 for reopening this.
+1 for reopening this.
Another +1 here
Not sure if helpful in any way, but what I believe is happening is:
Well, I'm not really sure that this is the exact situation here. But if it is... can't we skip the first pushState in any way? Or probably better... Rails knows the request.method for every request. Can't turbolinks use this and skip first pushState() for pages rendered after method = "POST"?
And I'll answer myself :)
... probably we can't.
I just commented the first @history.replace in controller.coffee -> startHistory() which seemingly solved the problem. The form was resubmitted when we refresh the page. "Yey!" :)
startHistory: ->
@location = Turbolinks.Location.wrap(window.location)
@restorationIdentifier = Turbolinks.uuid()
@history.start()
# @history.replace(@location, @restorationIdentifier)
However two not really desired things happened.
Anyway... I'm out of ideas... will look for some other workaround. Maybe the easiest one is to have fallback route when I'm missing the index. In my case (devise), I'll just redirect
get 'users', to: redirect('/users/sign_in')
Works for me for now. However any better suggestions are highly appreciated :)
+1 for reopening this
+1 for reopening this
Just stumbled open this issue today, I tried to disable turbolinks on that page, still to no avail.
I'm having the same issue.
+1
Experiencing the same issue on Chrome and Firefox. Works fine on Safari. However, on Safari I get #257 Can anyone corroborate?
Same problem here. Any ideas or fixes? Works fine when I remove turbolinks.
It's interesting that it works as expected in Safari only, but does not work in Chrome and FF..
+1 maybe just my bad karma for using a tool that reimplements fundamental browser behaviour in JS :(
Heh, yeah. But it seems to be working fine for a lot of people (me included – in previous projects). I suspect there was a regression somewhere along the line...
This should be reopened!
Guys, some info about this issue?
It's not an issue. I wish I had never opened this ticket :-)
On Fri, May 5, 2017 at 10:14 AM Victor Campos notifications@github.com
wrote:
Guys, some info about this issue?
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
https://github.com/turbolinks/turbolinks/issues/60#issuecomment-299475965,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAIBNryVfIk6yuRoVp2dp3i57Bqj1WPrks5r2y7LgaJpZM4H65gT
.
Some of us are still experiencing it though (or something similar).
Safari and Chrome gives different results. I think it is unexpected behavior.
@focused Yes, I have already opened a ticket. Please check #257 and corroborate
I have the same issue. The @notentered 's solution seems to fix a part of the problem.
@sblackstone not an issue that turbolinks have to figure out, but the occuring behaviour remains an issue. And still seem to happen
Does anyone have found a decent workaround ?
I just ran into this problem and after some Internet searching I only found this issue. It'd be really cool if we could get an answer on where the unintended behavior is so we can find a workaround.
Possible workaround idea: if a form comes back with errors, URL should be reset to the original form URL
Possible implementation idea: a Stimulus component (or something, that triggers JS code) can be added by SimpleForm automatically to forms, that have errors. This component (JS code) would update the page URL. The same SimpleForm element could add a hidden field containing a form original URL to forms.
Don't know if page refresh would preserve current form values, but at least users would end up on the same form page after a page refresh
Another idea: disable Turbolinks for form submissions
Another idea: use only remote forms and handle URL change manually
Bump.
I don't think this will cause an issue for my users in production, but I haven't even gotten to the beta test yet. I think that for complex forms with many fields (my use case, sadly), users accidentally or intentionally hitting refresh after a failed form submission is going to stress them out and make them angry based on the behavior Turbolinks is causing here...
I love Turbolinks, but this is IMO a glaring issue that needs to be fixed because it breaks normal user expectations of browser behavior.
Yeah, this Issue realy sux =(
Still happening =/
Turbolinks doesn't handle form submissions itself. It makes some recommendations on handling redirects after an XHR form submission, but leaves the submission implementation up to you.
In terms of refreshing a JS form submission, unfortunately I don't think the desired behaviour is possible due to the way that browsers work, and the currently available technologies. To help explain why, it might be useful to use a couple of examples.
Let's say we have a social network with an index containing list of posts that can be "Liked". Tapping the "Like" button POSTs an XHR to /likes. If the request were to error and we refresh the page, it reloads index, which is what we'd expect. It doesn't re-request the POST to /likes, or present an alert, warning of a form resubmission. That would seem odd! This _suggests_ that the browser's reload mechanism does not consider XHRs, when deciding how to reload a given page.
Now consider a blogging app where we visit /posts/new and POST a full page form to /posts via XHR. If it errors and we refresh the page we _might_ expect the browser to alert us to a form resubmission, but as our previous example showed, reloading doesn't consider XHRs. It just re-requests the current URL.
The requests are very similar in these cases, it is just the UI which alters expectations. This highlights some of the difficulties when formulating a general solution to this problem.
pushState adds a bit more complexity to the situation. It would make sense to update the URL via pushState in the second case (to /posts) to match how a browser typically operates when responding to full form submissions. However, pushState does not contain any details regarding _how_ a request was made, or of any form parameters sent. It is literally just pushing some state. pushState and XHRs are independent APIs, so it's not as if the browser can recognise an XHR POST followed by a change in the history, and know that it should mimic the behaviour of a traditional form request.
Once you take control of making requests via XHR and updating the address bar via pushState, the browser is like, "I'm done dealing with the history, I'll leave it to you!"
I can't find a simple explanation which defines browser reloading behaviour but here's what I think happens. On reload, the browser asks:
Typically the first answer will be, "via GET", and for the second answer it just looks at its current location in the address bar. This should hopefully explain the behaviour, after a form submission via XHR.
Dealing with forms in Turbolinks applications is a commonly faced problem, and it's something that may be handled in the future, but as the above hopefully demonstrates, it's a complex problem. I recommend checking out some of the solutions in https://github.com/turbolinks/turbolinks/issues/85 and adapting them to fit your case.
@domchristie the problem I'm seeing is that turbolinks seems to be changing the browser behaviour even in non XHR form submissions. Here is a minimal test case to reproduce the issue:
require "sinatra"
def layout(body)
<<-LAYOUT
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/turbolinks/5.2.0/turbolinks.js"></script>
</head>
<body>
#{body}
</body>
</html>
LAYOUT
end
get "/test" do
body = <<-GET_RESPONSE
<h1>I'm a GET REQUEST</h1>
<form action="/test" method="post">
<input type="submit" value="Submit me"/>
</form>
GET_RESPONSE
layout(body)
end
post "/test" do
body = <<-POST_RESPONSE
<h1>I'm a POST REQUEST</h1>
<form action="/test" method="post">
<input type="submit" value="Submit me"/>
</form>
POST_RESPONSE
layout(body)
end
This submits a form without XHR doing a regular POST request. If after submitting the form you reload the page, Chrome and Firefox use a GET http request. Safari does the right thing and shows an alert warning that the form will be resubmitted.
Now, if you remove the turbolinks script and do the same test, Firefox and Safari shows a the warning message. Chrome doesn't show the warning message but still reloads the page with a POST request.
@afcapel thanks for the test case and for highlighting the differences in non-XHR form requests when Turbolinks is installed. Based on this, and some of the comments above, I think we can deduce that this is a browser bug in Chrome/Firefox…
Whilst it seems unrelated, altering the history (via pushState or replaceState) causes problems with the confirm dialogs when refreshing after a POST 🤷♂️. Turbolinks doesn't deal with form submissions, so given the absurdity of the bug, I hope you can forgive the confusion around this issue!
We can _confirm_ the bug (pun intended) with the following example, which demonstrates the same behaviour. To clarify, any site which uses the history API before a form POST will be susceptible to this bug.
require "sinatra"
def layout(body)
<<-LAYOUT
<!DOCTYPE html>
<html>
<head>
<script>window.history.replaceState(null, null, window.location.href)</script>
</head>
<body>
#{body}
</body>
</html>
LAYOUT
end
get "/test" do
body = <<-GET_RESPONSE
<h1>I'm a GET REQUEST</h1>
<form action="/test" method="post">
<input type="submit" value="Submit me"/>
</form>
GET_RESPONSE
layout(body)
end
post "/test" do
body = <<-POST_RESPONSE
<h1>I'm a POST REQUEST</h1>
<form action="/test" method="post">
<input type="submit" value="Submit me"/>
</form>
POST_RESPONSE
layout(body)
end
As @notentered mentions above, Turbolinks replaces the state immediately after the page is initially loaded to bootstrap the history with some initial state. It _might_ be possible to remove this, but again, you'll eventually change the history at some point via navigation, and therefore hit this bug.
To back this up, this behaviour matches my own experience dealing with failing alert, confirm, and prompt dialogs in Safari iOS following a popstate event (https://github.com/turbolinks/turbolinks/issues/336). What's more, when experimenting with @afcapel's example with the dev tools open, I discovered that upon refreshing after a POST, Chrome issues another POST but does not display a confirm dialog.
Basically, browsers do weird things (with dialogs) when the history API is used 😫
If possible, I'd follow @notentered's recommendation and provide a fallback route which responds to GET requests to the same path, and redirect as necessary. Obviously this isn't ideal, but I'm not sure if there is a better solution at the moment.
Based on this, and some of the comments above, I think we can deduce that this is a browser bug in Chrome/Firefox…
I take that back! Fix + more details: https://github.com/turbolinks/turbolinks/pull/495
Most helpful comment
Same here.
If I remove Turbolinks 5.0.1 from my Rails 5.0.0.1 app, everything works as expected (Hitting F5 triggers a browser warning before resubmitting the form via POST).
If Turbolinks is active (while not actually being used on form submits), this default behaviour breaks. When hitting F5, the browser issues a GET to the current URL.
+1 for reopening this.