Ruby on Rails 3 Routing

Ruby on Rails Route (routes.rb)

Route configuration is stored in

Actions to routes.rb Changes to routes.rb
rails generate scaffold Something "resources :somethings" is added to routes.rb automatically
rails generate controller Something action get "controller/action" is added to routes.rb automatically
Add URL pattern manually match "/users/:id" => "users#show"

If more than one rule match an URL pattern, the rule on the top of the file take precedence

Ruby on Rails Route for Multiple Resources

Multiple resources: May contain multiple rows of data. An ID is needed to identify individual resource


Command to generate a scaffold for multiple resources

rails generate scaffold Billing

Changes to config/routes.rb

resources :billings

Automatically mapped:

HTTP method URL action Description
GET /billings index List all billings
GET /billings/new new Display a HTML form for creating a new billing
POST /billings create Create a new billing
GET /billings/:id show Display a bill with the specific id
GET /billings/:id/edit edit Display a HTML form for editing the bill with the specific id
PUT /billings/:id update Update a bill
DELETE /billings/:id destroy Delete the bill with the specify id

Command to find all route information in the same order in routes.rb

rake routes

Route output for accounts mapping a HTTP METHOD/URL to an action of a controller

Helper       METHOD URL     Map To Controller/Action                  Description 
    billings GET    /billings(.:format)                               {:controller=>"billings", :action=>"index"}
             POST   /billings(.:format)                               {:controller=>"billings", :action=>"create"}
 new_billing GET    /billings/new(.:format)                           {:controller=>"billings", :action=>"new"}
edit_billing GET    /billings/:id/edit(.:format)                      {:controller=>"billings", :action=>"edit"}
     billing GET    /billings/:id(.:format)                           {:controller=>"billings", :action=>"show"}
             PUT    /billings/:id(.:format)                           {:controller=>"billings", :action=>"update"}
             DELETE /billings/:id(.:format)                           {:controller=>"billings", :action=>"destroy"}

id can be accessed in the controller by


Rails URL link helper methods

Rails automatic generates helper methods to create url links

When append "_path" to the first column above in the "rake routes", it generates the following URL generation methods:

Method URL generated Description Action
billings_path /billings List all bills index
billing_path(@billing) /billings/:id Detail a bill new
edit_billing_path(@billing) /billings/:id/edit Edit page for billing edit
new_billing_path /billings/new Create page for billing show
<%= link_to 'Listing', billings_path %>
<%= link_to 'Edit', edit_billing_path(@billing) %>
<%= link_to 'New Billing', new_billing_path %>%>
<%= link_to 'Detail', billing_path(@billing) %>
<%= link_to 'Detail', @billing %>

For associate object

<%= link_to 'Billing Comment', [@billing, @comment] %>

Each of the helpers has another _url (like billings_url) which returns the host, port and path

Adding Query String(s) to link_to

Adding query string

<%= link_to 'Show', billing_path(@bill, :qstring=>"1") %>

The following will NOT work since the last parameter will be treated as HTML option instead

<%= link_to 'Show', @bill, :qstring=>"1" %>

Adding new Actions in a controller

To add a new Rails action "approve" for a resource

resources :billings do
  member do
    get 'approve'

To add a new Rails action "report" to the collection

resources :billings do
  collection do
    get 'report'

Ruby on Rails Resources Route - Singular Resources


resource :shop

Use the singular form of resource


Helper   METHOD URL         Map To Controller/Action              Description
       shop POST   /shop(.:format)                                   {:controller=>"shops", :action=>"create"}
   new_shop GET    /shop/new(.:format)                               {:controller=>"shops", :action=>"new"}
  edit_shop GET    /shop/edit(.:format)                              {:controller=>"shops", :action=>"edit"}
            GET    /shop(.:format)                                   {:controller=>"shops", :action=>"show"}
            PUT    /shop(.:format)                                   {:controller=>"shops", :action=>"update"}
            DELETE /shop(.:format)                                   {:controller=>"shops", :action=>"destroy"}

To possibly re-use the same controller, singular resources map to plural controllers.

Helper methods to create URL links

Route Helper URL Action Mapped To

Nested Resources

Create an associated model under another model

Generate a controller and a model

rails generate model Contact title:string description:text account:accounts
rails generate controller Contacts

Rails Model

class Account < ActiveRecord::Base
  has_many :contacts
class Contact < ActiveRecord::Base
  belongs_to :account

Routing for Nested Resources

Rails route information

resources :accounts do
  resources :articles

Rails route: rake routes

account_contacts GET    /accounts/:account_id/contacts(.:format)          {:controller=>"contacts", :action=>"index"}
                     POST   /accounts/:account_id/contacts(.:format)          {:controller=>"contacts", :action=>"create"}
 new_account_contact GET    /accounts/:account_id/contacts/new(.:format)      {:controller=>"contacts", :action=>"new"}
edit_account_contact GET    /accounts/:account_id/contacts/:id/edit(.:format) {:controller=>"contacts", :action=>"edit"}
     account_contact GET    /accounts/:account_id/contacts/:id(.:format)      {:controller=>"contacts", :action=>"show"}
                     PUT    /accounts/:account_id/contacts/:id(.:format)      {:controller=>"contacts", :action=>"update"}
                     DELETE /accounts/:account_id/contacts/:id(.:format)      {:controller=>"contacts", :action=>"destroy"}
            accounts GET    /accounts(.:format)                               {:controller=>"accounts", :action=>"index"}
                     POST   /accounts(.:format)                               {:controller=>"accounts", :action=>"create"}
         new_account GET    /accounts/new(.:format)                           {:controller=>"accounts", :action=>"new"}
        edit_account GET    /accounts/:id/edit(.:format)                      {:controller=>"accounts", :action=>"edit"}
             account GET    /accounts/:id(.:format)                           {:controller=>"accounts", :action=>"show"}
                     PUT    /accounts/:id(.:format)                           {:controller=>"accounts", :action=>"update"}
                     DELETE /accounts/:id(.:format)                           {:controller=>"accounts", :action=>"destroy"}

Rails Nested Resources URL Helper Methods

<%= link_to "Contact details", account_contact_path(@account, @contact) %>
<!-- same -->
<%= link_to "Contact details", url_for(@account, @contact) %>
<%= link_to "Contact details", [@account, @contact] %>
<%= link_to "Account details", @account %>

Nested Resources - Controller & View

Controller for Contacts

class ContactsController < ApplicationController
  def create
    @account = Account.find(params[:account_id])
    @contact = @account.contacts.create(params[:id])
    redirect_to account_path(@account)


<p>Add a contact:</p>
<%= form_for([@account,]) do |f| %>
  <div class="field">
    <%= f.label :title %><br />
    <%= f.text_field :title %>
  <div class="field">
    <%= f.label :description %><br />
    <%= f.text_area :description %>
  <div class="actions">
    <%= f.submit %>
<% end %>

Controller Namespace

Add prefix namespace to URL

namespace "partner" do
  resources :deals, :billings
  • Prepend the /partner/ to the URL
  • Use Partner::DealsController to handle the URL

Rails will create:

partner_deals GET    /partner/deals(.:format)                   {:controller=>"partner/deals", :action=>"index"}
                  POST   /partner/deals(.:format)                   {:controller=>"partner/deals", :action=>"create"}
 new_partner_deal GET    /partner/deals/new(.:format)               {:controller=>"partner/deals", :action=>"new"}
edit_partner_deal GET    /partner/deals/:id/edit(.:format)          {:controller=>"partner/deals", :action=>"edit"}
     partner_deal GET    /partner/deals/:id(.:format)               {:controller=>"partner/deals", :action=>"show"}
                  PUT    /partner/deals/:id(.:format)               {:controller=>"partner/deals", :action=>"update"}
                  DELETE /partner/deals/:id(.:format)               {:controller=>"partner/deals", :action=>"destroy"}

To route URL /partner/deals to DealsController without the Partner:: module prefix

scope "/partner" do
  resources :deals, 

To route to the same controller (Partner::DealsController) without the URL /partner prefix

scope :module => "partner" do
  resources :deals

Ruby on Rails Non-Resourceful Routes

Define a URL pattern with controller/action name

# URL: /accounts
# URL: /accounts/view      
# URL: /accounts/view/1   params[:id] will set to 1
match ':controller(/:action(/:id))'

Define multiple Hash key for params

# URL /accounts/view/13/345?code='text'
match ':controller/:action/:first_id/:second_id'

Parameters is accessible by


Define static text segments

# URL /accounts/view/13/some_static_text/345
match ':controller/:action/:id/some_static_text/:second_id'

Static URL pattern

Mapping a URL pattern to a specific Rails controller and action

match 'accountreview/:id' => 'accounts#report'

Set default value for parameter params[:fee] to "yes"

match 'accountreview/:id' => 'accounts#report', :defaults => { :fee => 'yes' }

Create link helper method

match 'signout' => 'account#signout', :as => :out
  • ":as" create out_path and out_url helper methods automatically. out_path will return /signout

Options for Resources Routing

resources :trades, :controller => "trades"
Options supported Example Description
:controller resources :stocks, :controller => "admin/trades" Specify the controller handling the request
:constraints resources :accounts, :constraints => {:id => /[0-9]+/} :id must be all digits in /accounts/:id
:as resources :accounts, as "users" Use "users" as prefix for path helper method like new_user_path
:path_names resources :accounts, :path_names => { :new => 'create', :edit => 'update' } Use /accounts/make and /accounts/1/update for the new and edit URL
:only resources :accounts, :only => [:index, :show] Only route these actions
:except resources :accounts, :except => [:destroy] Do not route these actions
:path resources :accounts, :path => "vip" use /vip instead of /accounts

Define singular/plural of a word

ActiveSupport::Inflector.inflections do |inflect|
  inflect.irregular 'person', 'people'

Apply Constraint to a Route

Limit HTTP method

Apply the URL pattern to HTTP post only

match 'accountreview/:id' => 'accounts#report', :via => :post

Apply the URL pattern to multiple HTTP methods

match 'accountreview/:id' => 'accounts#report', :via => [:get, :post]

Apply Regular Pattern Constraint

Accept URL pattern with id composed of lower case letters only

match 'accountreview/:id' => 'accounts#report', :id => /[a-z]+/

Match URL begins with "RA"

match '/:id' => 'accounts#show', :constraints => { :id => /RA.+/ }

Constraint by Request Object

match "reviews", :constraints => {:subdomain => "partner"}
  • Apply the pattern with request.subdomain returns "partner"
  • Can use any method in the request object as a constraint

Determine a Constraint by the matches? method of an Object

class MyConstraint
  def initialize

  def matches?(request)
MyApp::Application.routes.draw do
  match "/private" => "private#index",
    :constraints =>

Route Globbing

Map URL accounts/11/04/review or accounts/review using wild card

match 'accounts/*rest' => 'accounts#review'
  • params[:rest] set to "11/04/review" and "review" respectively

Use of multiple wild card

match 'accounts/*rest/contact/*cont' => 'accounts#review'


Redirect a URL pattern

match "/private" => redirect("/denied")

Use of dynamic segment mapping

match "/private/:name" => redirect("/denied/%{name}")

Using Ruby Code block to determine the redirect target

match "/private/:name" => redirect {|params| "/denied/#{params[:name]}" }
match "/private/:name" => redirect {|params, req| "/denied/#{params[:name]}/#{}" }

Trouble shooting routes

Display the routing in the same order that how a match is found in routes.rb

rake routes

Only display the Rails route for a specific controller

CONTROLLER=accounts rake routes

Unit Testing of Rails Routes

Unit test whether a set of options will generate a specific path

assert_generates "/accounts/1", { :controller => "photos", :action => "show", :id => "1" }
assert_generates "/about", :controller => "pages", :action => "about"

Unit test whether a specific URL pattern will route to the target. (Inverse to assert_generates)

assert_recognizes({ :controller => "accounts", :action => "show", :id => "1" }, "/accounts/1")
assert_recognizes({ :controller => "accounts", :action => "create" }, { :path => "accounts", :method => :post })

Unit test URL link helper method

assert_recognizes new_account_url, { :path => "accounts", :method => :post }

Conduct the unit route testing in both ways

assert_routing({ :path => "accounts", :method => :post }, { :controller => "accounts", :action => "create" })

link_to helper method

Use ActionView helper method

link_to "User", user_path(@user)    # => <a href="/users/123">User</a>

Use a Model instance

link_to "User", @user               # => <a href="/users/123">User</a>

Specify controller, action and Id

link_to "User", :controller => "users", :action => "show", :id => @user     # => <a href="/users/show/1">User</a>
link_to "Users", users_path         # => <a href="/users">Users</a>

Generate the custom HTML code inside the anchor tag

<%= link_to(@user) do %>
  <b><%= %></b>
<% end %>
# => <a href="/users/1">

Specify a CSS Style

link_to "Users", users_path, :id => "user_id", :class => "user_style"
# => <a href="/users" class="user_style" id="user_id">Articles</a>
link_to "Users", { :controller => "users" }, :id => "user_id", :class => "user_style"
# => <a href="/users" class="user_style" id="user_id">Articles</a>

Add a HTML anchor

link_to "Section A", user_path(@user, :anchor => "a")
# => <a href="/users/1#a">Section A</a>

Add query string

link_to "User", user_path(@user, :q1 => "v1", :q2 => "v2")  # => <a href="/users/123?q1=v1&q2=v2">User</a>