Lets say I am creating a new Foo using a form and a standard Rails restful controller, which looks something like this:
class FoosController < ApplicationController
...
def index
@foos = Foo.all
end
def new
@foo = Foo.new
end
def create
@foo = Foo.create(params[:foo])
if @foo.save
redirect_to foos_path, :notice => 'Created a foo.'
else
render 'new'
end
end
...
end
So, if I use the standard restful controller (as above), then when I'm creating the Foo I am at example.com/foos/new
, and if I submit the form and it saves correctly I'm at example.com/foos
showing the index action. However, if the form is not filled correctly the form is rendered again and error messages are shown. This is all plain vanilla.
However, if errors are shown, the form page will be rendered but the URL will be example.com/foos
, because the CREATE action posts to that url. However, one would expect to find Foos#index at example.com/foos
, not the form they just submitted now with error messages added.
This seems to be Rails standard behavior, but it doesn't make a lot of sense to me. Obviously I could redirect back to new instead of rendering new from the create action, but the problem with that is the error messages etc. would be lost along with the partially complete Foos in memory.
Is there a clean solution for this problem, a way to send people back to example.com/foos/new
when there are errors in the new Foo form they submitted?
Thanks!
You could hook into rails routing by adding this in an initializer: https://gist.github.com/903411
Then just put the regular resources in your routes.rb:
It should create the routes and behaviour you are looking for.
You could use Rack::Flash to store the parameters you wanted in the user's session and then redirect to your form url.
You can set up the routing manually, if you're that concerned about what URL is going to show. For what you want, you can have a
GET
to/foos/new
render your form, and aPOST
to the same URL do the creation:This should work without requiring any changes to your controller (yay!) - all three actions from your example are taken care of. The few disclaimers:
map.resources
have failed horribly - unless you're more familiar with this than me, or Rails 3 routing is better (both easily possible), you'll have to do this for every route to the controller./:id
,(.:format)
, etc. to the routes that need them (none in this example, but see #2).Hope this helps!
Edit: One last thing - you'll need to hard-code the URL in your
form_for
helper on/foos/new.html.erb
. Just add:url => create_foo_path
, so Rails doesn't try to post to/foos
, which it will by default (there might be a way to change the creation URL in the model, but I don't know of it, if there is one).To answer your comment on another answer:
I don't think so; URLs are tied directly to routing, which is tied into a controller and action pair--the rendering layer doesn't touch it at all.
To answer your original question, here's information from another similar question I answered.
As you've found, by default when you specify
resources :things
, the POST path for creating a new thing is at/things
. Here's the output forrake routes
:It sounds like you want something more like this:
Although not recommended, you can get this result with the following route:
You would also need to modify your forms to make them POST to the correct path.