RESTful Routing in Rails 3
This post deals with generating RESTful routes in Rails 3. If you want to look at the basics of routing (which also helps in understanding RESTful routes), take a look at Routing in Rails 3.
RESTful routes is quite a large topic and it’s quite possible to write quite a few posts (or even a whole book) about it. Instead of getting caught up in REST itself I’m only going to look at the basics and try to understand how we use it in Rails.
In broad terms, using the REST support in Rails 3 gives you automatic best practices and exposes a RESTful interface to the outside world. In my very limited experience with Rails I’ve been mostly concerned with the first benefit (best practices).
Standard RESTful Controllers
Rails helps us to create RESTful routes through the resources method. To get started, I’ve put the following line in my config/routes.rb file:
resources :products
Let’s take a look at what this actually did by running rake routes.
(If you’re unfamiliar with the output of this command – the first column is the name of the route, the second is the HTTP verb, the third is the URL and the last one is the action it maps to.)
So for the price of a single line of code we get 7 routes, including 4 named routes. You can also see the different actions Rails is expecting us to create – index, show, new, create, edit, update and destroy. That’s the side of the bargain we have to keep up in order to easily get access to RESTful routes. If you’ve worked on a Rails 3 application those actions will probably look very familiar to you.
Understanding the RESTful Routes
Typically, the create and update operation involve two steps – two requests. For example, if we want to create a new product we will need:
- An action that results in a ‘new product’ form being displayed
- An action that creates the new product when the form is submitted
In this way the new action is associated with the create action and the edit action is associated with the update action – the first shows the user a form while the second will process the form when it is submitted.
This also explains why we don’t have named routes for the create and update actions – these actions will involve submitting a form and therefore we don’t need to generate links to these actions. (Rails will however generate form URLs within the form_for method)
Sticking with the products example, let’s run through the different actions and see if they make a bit more sense now:
- Index – display a list of products
- Show – display a single product
- New – display a ‘new product’ form that allows the user to enter the data for creating a new product
- Create – create a new product when the form from the new action is submitted
- Edit – display an ‘edit product’ form that allows the user to modify the data for an existing product
- Update – update an existing product when the form from the edit action is submitted
- Delete – delete an existing product
Create and Update
I mentioned that we don’t have named routes for the create and update actions – rails will generate these URLs when we use the form_for method.
For example, my new action might look like this:
When I now invoke the form_for method in my view,
form_for(@product)
Rails will generate the correct URL for the form.
<form action=“/products” method=“post”>
So that takes care of the new action, but what about updates? For example, my edit action might look like this:
Using the same form_for method as before,
form_for(@product)
Again Rails generates the correct URL.
<form action=“/products/1” method=“post”>
How did Rails know when to generate which URL? Turns out Rails is smart enough to ask the product being passed in product.new_record? and rendering the correct URL based on the answer. We also don’t need to go and add this method to our model – it’s included through ActiveRecord. Isn’t Rails neat?
What I’m highlighting here is obviously the default behavior – form_for has the necessary overloads for you to change the default when necessary.
The PUT and DELETE verbs
If you were paying particularly close attention you would have noticed that the method Rails generated for our update form was POST, while the verb specified in our update route is PUT. What’s up with that?
It turns out browsers can only really handle two verbs – GET and POST. This means that pretty much all forms in web browsers will be submitted via POST. To get around this Rails will add a hidden field to our form called _method with the value set to either PUT or DELETE. On the server Rails will then pick up this field and change the method appropriately.
This isn’t something you need to worry about, but it’s probably a good idea to be aware of it.
Limiting the Routes Generated
As we’ve seen the resources method will by default generate 7 different routes. You may wish to restrict this – for example, you might wish to not have the destroy route.
resources :products, :except => [:destroy]
Alternatively you could also specify only the routes you want generated.
resources :products, :only => [:index, :show]
There’s much more to it
I have only really scratched the surface here. If you dig deeper you will find things like nested resources which in certain scenarios can make your life a whole lot easier. My brief look at RESTful routing is really only meant to serve as an introduction to help you on the journey.
If you want to play around with the routing, I have pushed the code I used to test all of this onto github.
Happy coding.