Ruby on Rails/Routing
Because Routing is such an important part of Rails we dedicated a whole chapter to Routing (even though they are part of ActionView).
For example, if you want to display the product with the id 4, you will use a link similar to products/4. So Rails will figure out, that you want to show the information that belongs to the product with the id 4.
Routing also works when you want to link somewhere from one point of your application to another point. If you want to go back from the products view to the index overview that displays all products, you may place something like this in your view:
<%= link_to 'Back', products_path %>
When writing your own routes inside routes.rb, keep in mind, the lower the route is inside your file, the less priority it has.
Understanding Routes and Routing
editRESTful routes
editRESTful routes are the default routes in Rails. To get a more detailed technical view on REST, check out the Wikipedia article.
Basically REST provides a way of communication inside your application and all requests that exist from external sources (just as a browser request). To understand these principles better, take a look the following table:
HTTP Verb | URL | Controller | Action | used for |
---|---|---|---|---|
GET | /products | Product | index | display all products in an overview |
GET | /products/new | Product | new | return an HTML form for creating a new product |
POST | /products | Product | create | create a new product |
GET | /products/1 | Product | show | display a specific product |
GET | /products/1/edit | Product | edit | return an HTML form for editing a product |
PUT | /products/1 | Product | update | update a specific product |
DELETE | /products/1/ | Product | destroy | delete a specific product |
As you can see, all the actions of REST are already in our scaffolded controller. Keep in mind that RESTful routes reference a single object (products in this case). These 7 actions would result in a single route inside routes.rb:
map.resources :products
With a RESTful resource, it's easy to link the different views together or link to a specific view. With REST, Rails provides us some helpers to get to our desired location:
- products_url & products_path => redirects us to the index overview and edit view for our products (note the plural)
- new_product_url & new_product_path => will lead as to the form that creates a new product
- edit_product_url & edit_photo_path => provides us with an edit-form for a specific product
- product_url & product_path => is responsible for showing, deleting and updating a product
While *_path will create a relative path to, *_url provides the whole URL
- _path => /products
- _url => http://localhost/products
You will very likely need more than one REST route. You can easily write multiple REST routes into a single:
map.resources :products, :categories, :customers
You will come across many similar constructs like our products-category relation:
class Category < ActiveRecord::Base
has_many :products
end
class Product < ActiveRecord::Base
belongs_to :categories
end
HTTP Verb | URL | Controller | Action | used for |
---|---|---|---|---|
GET | /products/1/categories | Category | index | will show you an overview of the categories for product with the id 1 |
GET | /products/1/categories/new | Category | new | will give you an HTML form to create a new category for product with id 1 |
POST | /products/1/categories | Category | create | will create a new category for product with id 1 |
GET | /products/1/categories/1 | Category | show | shows you the categories with id 1 that belongs to your product with id 1 |
GET | /products/1/categories/1/edit | Category | edit | gives you an HTML form to edit your category with id 1 that belongs to product with id 1 |
PUT | /products/1/categories/1 | Category | update | updates category with id 1 that belongs to product with id 1 |
DELETE | /products/1/categories/1 | Category | destroy | deletes category with id 1 that belongs to product with id 1 |
As with resources that are not nested, you will be able to access all *_url and *_path helpers e.g. products_categories_path or new_product_category_url
These path need to be present in your routes.rb in an similar maner to your model:
map.resources :products, :has_many => :categories
if you need to add more than one association, put these in []
which is the same as the following route, only shorter
map.resources :magazines do |magazine|
magazine.resources :ads
end
With this way, you can nest as many resources as you want, but you should try to keep the level of nesting as low as possible. So one nested resource is ok, but try to avoid 2 or more. To avoid these problems, we can use "shallow nesting"
If we want to add supplier for specific categories, we may end up with something like
map.resources :publishers, :shallow => true do |publisher|
publisher.resources :magazines do |magazine|
magazine.resources :photos
end
end
or in short:
map.resources :products, :has_many => { :categories=> :suppliers }, :shallow => true
There are many more advanced features for routing. More infos and instructions can be found in the official Rails guides.
Regular Routes
editEven though RESTful routes are the encouraged way to go, you can also use regular routes inside your application. When working with regular routes, you give Rails some keywords and it will map the proper path for you. One of these default routes is already inside your routes.rb (this time we don't use .resources but .connect)
map.connect ':controller/:action/:id'
will for example be a browser request similar to products/show/2
If you are familiar with other languages that focus an the web, you may wonder how query strings inside the URL are handles: Rails automatically provides these parameters inside the params hash
So if you take the example above and add products/show/2?category=3, we would be able to access the category id with params[:category_id].