Reputation: 600
When a user makes an invalid create request for a resource, I want to send them back to the form and show them an error. As far as I can tell, calling render "new"
is the standard way to do it.
This seems like a bad idea to me, because the create request has taken the user to /resources, whereas my "new" form is otherwise at /resources/new. If I use render "new"
, the URL in the address bar will not reflect what the user sees. If they make a GET request there, they'll end up on a different page.
I thought I could solve this problem by using redirect_to new_[resource]_path
, but if I do that I lose access to the form data and errors. Surely this is not an uncommon problem. Is there a better way to deal with it?
I have the same problem with edit/update and other form/submit action pairs.
Upvotes: 1
Views: 1585
Reputation: 6603
class ResourcesController < ApplicationController
def new
@resource = Resource.new(resource_params)
if resource_params.present?
@resource.validate
end
end
def create
@resource = Resource.new(resource_params)
if @resource.save
redirect_to @resource, notice: 'Resource has been created'
else
redirect_to new_resource_url(resource: resource_params)
end
end
private
def resource_params
params.fetch(:resource, {}).permit(...)
end
end
I asked this myself as well in my early beginner days, on why Rails scaffold generator generates the def create
action to render :new
if saving failed, instead of redirecting to the correct URL just something like above, which would confuse the users because their URL would have changed from /resources/new
into /resources
even though they would still see the exact same Resource form on the page, and therefore they would not be able to reload the page or copy this /resources
URL (for example, if they want to share this URL to someone else), because should they share this /resources
URL, the others would see a list of Resources on the page instead of what the original user would have expected to see from the copied URL: which is the form page.
After the user submits the form, the URL they see on the address bar should have changed into POST http://localhost:3000/resources
instead of just simply http://localhost:3000/resources
. The browser hides the HTTP Method being used, that's why this leads to their possible confusion that /resources
seems to have been both sometimes: a form page, sometimes a list of resources page. However, speaking of UX, every time anyone enters something or pastes something in the URL address bar of the browser, it is always automatically implied to be doing a GET
request. Therefore, it makes sense for the browser-developers to just simply hide the HTTP method (i.e. GET
in particular) from the users as to not confuse them.
From my answer above, I only used something like this once before (because there was a certain action that demanded me not to change the URL from the referrer form page). However, I normally render :new
instead of redirect_to new_resources_url
, simply because:
a redirect_to new_resource_url(resource_params)
would take twice as much time and data-transmitted than simply rendering :new
. Why? Because you redirect (opening up a new request) with the exact same parameters anyway. Just imagine if your form page is soooo big, and has so many input fields.
and also that there's a limit to how long a URL can be, of which won't guarantee to work if you have a very big form with very long text fields. See this SO
As you have said though, why not just POST /resources/new
instead of POST /resources
when the form is submitted, right? This will solve the redirect_to new_resource_url(resource_params)
problem I've shown above, because the URL after form-submit would have been the same and you can just simply render :new
, then. And I actually agree on that, and I've used something like this also before long time ago. The main reason I don't use this is that it is not inline with REST standards. That is: POST /resources/new
means that you're creating a Resource object "inside" the resources/new
location, which then means by REST, after submitting the form, I would and should be able to access this newly created resource by doing something like GET /resources/new/the_newly_created_record
, except that... you can't.
But you can still use POST /resources/new
, although I would not recommend it on a normal Rails application like yours, and however strictly discourage it on an API-based Rails application.
Upvotes: 3
Reputation: 15525
You may be overthinking this. How about get /resources
the index page vs post /resources
the create action? Same url in the address bar!
It's not a problem. Neither a technical problem or an aesthetic problem.
render "new"
means: render this template, not: go to this route. And although templates often have the name of the corresponding action, it's not a requirement.
Upvotes: 1