1. An Introduction to Routes1.1 What and WhyThis patch implements native Ruby rewriting for Rails, thus shifting the responsibility of URL parsing from the webserver to Rails itself. This has been a requested feature for two primary reasons.
1.2 Diving InRoutes have been designed to be fully customizable by the average Ruby programmer. You’ll no longer have to be a htaccess wizard to have pretty URLs for your site. Routes are defined in config/routes.rb. This file is a typical ruby source file which contains a document similar to
ActionController::Routing.draw do |map| map.connect ‘:controller/:action/:id‘ end Instead of wading through the tedious and obvious, let’s dive right in. Example 1—Setting A Default ControllerLet’s say you’re one of those cool kids with a blog, and you’d like http://www./ to show your recent posts. Case 1—BlogController#indexLets say your BlogController’s index action is already setup to show the list of recent posts. To specify the default controller, we add :controller => ‘blog’ to the default route:
ActionController::Routing.draw do |map| map.connect ‘:controller/:action/:id‘, :controller => ‘blog‘ end As an additional perk, Routes will opt for the shortest path possible, so url_for :controller => ‘blog’, :action => ‘index’ will generate a url such as http://www./. Case 2—BlogController#recentLets suppose that for whatever reason, your BlogController displays the recent posts with another action. We need to add a new Route that matches an empty path and points to BlogController’s recent action.
ActionController::Routing.draw do |map| map.connect ‘‘, :controller => ‘blog‘, :action => ‘recent‘ map.connect ‘:controller/:action/:id‘ end Notice that we put our new route before the default Rails route. Routes are recognized and generated in the order they are defined. By placing our custom route before the default Rails route, we can be assured that url_for :controller => ‘blog’, :action => ‘recent’ will generate a URL with an empty path, such as http://www./. Note that if public/index.html exists, it will be served and Rails will not see the request. Be sure to delete the Congratulations page that ships with Rails. Example 2—Setting up date-based URLsSuppose you want to add a feature to your blog that let’s your visitors view posts by date. You’d like to allow them to browse by year, month, and day, and you already have an action which uses query or post parameters named year, month, and action. The ideal URL for this looks like http://www./2005/02/14, with the month and day components being optional. Because you’re a sane person, you decide that the date order should be YYYY/MM/DD, rather than some arcane order such as MM/DD/YYYY. Once again, we will want to add our custom route before the default Rails route. A first try at this might yield
map.connect ‘:year/:month/:day‘, :controller => ‘blog‘, :action => ‘by_date‘Although this will successfully match http://www./date/2005/02/14, it will fail to do so for tt>http://www./date/2005/02—we need to mark the :month and :day components as optional. To do so, we add :month => nil to our route:
map.connect ‘date/:year/:month/:day‘, :controller => ‘blog‘, :action => ‘by_date‘, :month => nil, :day => nil Now our custom route will recognize URLs such as http://www./date/2005/02 or even http://www./date/2005. On the flip side, our custom route will also be used automatically when URLs are generated with the standard forms helpers such as link_to and url_for. Now we run into another problem—our new route is too general, and it will catch all three-component URLs—such as posts/show/10. To combat this, we must tell place some requirements on our path components. Requirements are placed using a :requirements sub-hash like so:
map.connect ‘date/:year/:month/:day‘, :controller => ‘blog‘, :action => ‘by_date‘, :month => nil, :day => nil, :requirements => {:year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/} Example 3—Posts by CategoryLets move back to your BlogController. Suppose each of your posts belong to a category, and that we would like URLs to show items based on category, such as http://www./posts/rails. Lets assume that you also use the category “all” to mean show all categories. A quick route for this would be:
map.connect ‘posts/:category‘, :controller => ‘blog‘, :action => ‘posts‘The problem with this route is that your link_to statements will all have to include :category => ‘all’. It would be nicer if our templates could contain
<%= link_to ‘Posts‘, :controller => ‘blog‘, :action => ‘posts‘ %> We can achieve this by giving the route a default value for :category:
map.connect ‘posts/:category‘, :controller => ‘blog‘, :action => ‘posts‘, :category => ‘all‘ An added bonus is that the URL generated for the above link_to will omit the extraneous ‘all’ component, and be displayed as http://www./posts. |
|