Suppose I have a Rails controller method, which is executed when the user submits a form. Now, the user submits the form, and while the method is running (and hasn't rendered the next page to the user), the user hits "Refresh". What is going to happen? Will the method stop running and restart, or will there be another thread to run the method once more?
I had to find the answer out for this myself, here is what I found (using Network tab on chrome inspector)
The browser sends the following requests:
GET /profile/123/edit (user brings up edit form)
PUT /profile/123 (user submits form)
The users hits refresh, which causes:
GET /profile/123/edit
In other words, it doesn't re-submit the form, it re-brings up the edit form.
Now... if instead of hitting refresh they hit submit a second time, that will send a second
PUT /profile/123
which will call your controller method a second time.
If that is a problem, you may need to add some logic to ignore or otherwise handle subsequent submits (simple state machine?). Remember the days when e-commerce sites had a message like "Do not hit submit twice" after you bought something... they didn't have that logic :)
Related
Quick question here.
I'm creating a 3-step form for a user - all AJAX (and using Devise). The user is created on the first step, and updated on the second two steps.
Now, the issue is that if a user hits the back button in their browser to go back to the first step, the Devise automatically changes the form action to update. But, the my update action renders partials that should only be rendered in steps 2 and 3 via Ajax.
How can I make it so that the user is logged out when hitting the back button so that the first form is always a new_user form?
One solution is to disable back button in browser at all.
You can use a modal to implement the three steps. If you are using Ajax, use it at full.
By this, there is no "back" button on the browser. But you can still have "back" button on your modal window, in this case the back option is totally in your control.
Add
For usability you should allow users to update their info at any time, instead of forcing them to complete all right after signed up.
I don't know what your next two steps are. But you can
Setup the update method to render the next two steps if an user has not finished them, or render other info if finished.
Show a notice if an user is signed in but has not finished the two steps.
By these you should be able to ensure whatever the user do on their browser, he can see what he need to do next. These should be applicable to either Ajax or no Ajax.
I know that whenever you submit a form, you will refresh a page. But is there a way of using javascript or whatsoever that allows the webpage to refresh one more time after a submit button is being input?
Thank you guys so much.
I am guessing that what you need to implement is the Post, Redirect, Get pattern, which is the recommended way in Grails applications. if you type grails generate-controller [somedomainclassname], you will see that that controller actually employs this pattern.
It works as follows:
Your form submits to a action inside a controller, let's call it save()
Your save() action then performs the necessary operations to actually save the object, when it is done, it sends the browser a 'redirect', much like this: redirect(action: "show", id: mySavedObject.id)
This will cause the browser to issue a GET for the url /mycontroller/show/{id}
That request is picked up by the show action of your controller. It then goes on to display the object that was just created.
This approach plays well with HTTP semantics and avoids annoying "do you want to repost your form data" questions for the end user.
In my Rails controller method, which is executed when the user submits a form, there is a Ruby code sleep(60), telling it to wait for a minute. One user submits the form, and while the execution is "sleeping", another user submits the form. Will the second user have to wait for the first user to finish, or will the execution of the controller start for the second user?
Both users will wait for 60 seconds only, they will not depend on each other.
As request will be processed separately for each other.
Hence no dependency
I am working on a web application that involves the user filling out a multi-step form that spans several pages. The form has tabbed navigation across the top (these links do not submit the current page) and a next button at the bottom (which does submit). I am considering several strategies for handling form submission/validation:
one action method and view per form page. When you hit next, it submits the form to the action method for the next page. If there are validation errors, you are redirected back to the previous page:
URL's are descriptive and can be copy-pasted
Only redirects in the error case
Since the redirect does not have the form data, we lose context about the submission which makes it hard to display certain error messages
The same validation logic works for redirecting the user if they try to visit a step in the flow that they aren't ready for yet
one action method and view per form page. When you hit next, it submits the form to the current page action. If there are validation errors, the same view is returned. Otherwise, we redirect to the next page action:
URL's are descriptive and can be copy-pasted
Redirects are very common (not sure if this is bad)
When displaying validation errors, we are in the same request as the form submission so we have full access to the invalid input
Have to pass additional context if we want the ability to, for example, add a "Previous" button which also submits
one action method for ALL pages. URL's contain additional context about the step being submitted (e.g. MyController/MyAction/{step}). The controller message selects which view page to return depending on validation and the current step.
URL's are not descriptive (e. g. if I submit step 1 to go to step 2, then the URL the user sees will be the same regardless of whether page 1 (invalid) or page 2 is returned
No redirects
When displaying validation errors, we are in the same request as the form submission so we have full access to the invalid input
A different method I haven't listed here
I have tried to enumerate what I see as some of the pros and cons of each method, but I would be interested to know:
What are other pros and cons of these methods? Are mine correct? Could some of the cons I've listed be designed around?
Is there a standard approach to this problem which I should be using? If so, why is it the standard approach?
I would highly recommend option 2 with a minor modification. You may want to think about also creating one view model per action/view as well. If you have one model that spans all the pages, validation will occur across ALL properties, meaning that even though the user can only edit part of the model on each screen, they could get validation warnings for properties they can't see. We did this recently in a project and it worked beautifully. You have to do some data manipulation in the back-end to combine everything back together, but it was worth it in the end.
As you said, your URLs would be deep-linkable, which means users can Copy/Paste, and more importantly, they can add the page as a favorite in their browser, allowing them to come back to the same place very easily. In my opinion this makes option 3 obsolete.
You will also benefit from the fact that all of your logic for navigation is occurring in one place. You'll have to store the state of the "wizard" on the client (which page you're currently on) so that your controller knows what to do on submit. You'll want to analyze the state of the wizard and make a decision for where the user needs to go next. If you go with option 1, you won't know where you "came from" and server-validation errors will be difficult to display to the client. This is a beautiful example of the POST - REDIRECT - GET pattern. Each page would have 2 actions, a GET that takes simple ids, and a POST which takes more complex models. Post the server, figure out where to go next, redirect to a GET.
Lastly, consider your previous button simply linking directly to the previous step, instead of submitting the form. Otherwise, the user could potentially get stuck on an invalid step. This happened to us and again, worked very nicely.
Hopefully this was helpful. Good luck!
A common web problem is where a user clicks the submit button of a form multiple times so the server processes the form more than once. This can also happen when a user hits the back button having submitted a form and so it gets processed again.
What is the best way of stopping this from happening in ASP.NET MVC?
Possibilities as I see it are:
Disable the button after submit - this gets round the multiple clicks but not the navigation
Have the receiving action redirect immediately - browsers seem to leave these redirects out of the history
Place a unique token in the session and on the form - if they match process the form - if not clear the form for a fresh submit
Are there more?
Are there some specific implementations of any of these?
I can see the third option being implemented as an ActionFilter with a HtmlHelper extension in a similar manner to the anti-forgery stuff.
Looking forward to hearing from you MVC'ers out there.
Often people overlook the most conventional way to handle this which is to use nonce keys.
You can use PRG as others have mentioned but the downside with PRG is that it doesn't solve the double-click problem, it requires an extra trip to the server for the redirect, and since the last step is a GET request you don't have direct access to the data that was just posted (though it could be passed as a query param or maintained on the server side).
I like the Javascript solution because it works most of the time.
Nonce keys however, work all the time. The nonce key is a random unique GUID generated by the server (also saved in the database) and embedded in the form. When the user POSTs the form, the nonce key also gets posted. As soon as a POST comes in to the server, the server verifies the nonce key exists in its database. If it does, the server deletes the key from the database and processes the form. Consequently if the user POSTs twice, the second POST won't be processed because the nonce key was deleted after processing the first POST.
The nonce key has an added advantage in that it brings additional security by preventing replay attacks (a man in the middle sniffs your HTTP request and then replays it to the server which treats it as a legitimate).
You should always return a redirect as the HTTP response to a POST. This will prevent the POST from occuring again when the user navigates back and forth with the Forward/Back buttons in the browser.
If you are worried about users double-clicking your submit buttons, just have a small script disable them immediately on submit.
You might want to look at the Post-Redirect-Get (PRG) pattern:
This really isn't MVC specific, but the pattern we follow on our web pages is that actions are performed with AJAX calls, rather than full page POSTs. So navigating to a url never performs an action, just displays the form. The AJAX call won't be in the history
Along with the disabling of buttons, you can add a transparent div over the entire web page so that clicking does nothing. We do this at my work and add a little friendly label saying processing request..
The most elegant solution I found was to use ActionFilters:
Blog post is here