breaking into the unknown…

routes in rails

1 Comment

routes in rails is basically a URL, which user type in the browser to access any particular part of your application. routes is defined in configuration/routes.rb  file. This file contain all the URL of your Application. Rails provide you a number of concise way to define a URL or a route in rails term.

To get the list of all the routes available in your application, run below command on your project directory

$ rake routes # it will list all the routes in your application


$ bundle exec rake routes # It is same as above command, we are just running it in context of current bundle. the above command may cause problem some time, but this will always work. get more detail on bundle exec in this post.

If you are working on ubuntu, you can filter the listed routes with grep command as below

$ bundle exec rake routes | grep photos # It will list only the route containing photos.

photos               GET                   /photos(.:format)                     photos#index
                     POST                  /photos(.:format)                     photos#create
new_photo            GET                   /photos/new(.:format)                 photos#new
edit_photo           GET                   /photos/:id/edit(.:format)            photos#edit
photo                GET                   /photos/:id(.:format)                 photos#show
PUT                                        /photos/:id(.:format)                 photos#update
DELETE                                     /photos/:id(.:format)                 photos#destroy

O.K……….now how you will read them.

First column : It represent named_helper, which you can use in you view file

NOTE : you can use the named_helper either with path or url suffix. with path suffix it generate the relative path while with url suffix it  will generate the absolute path. So, for  a example you can use new_photos_path or new_photos_url.

Second Column : It will tell about HTTP verb.

NOTE : same named route may go to different action depending on the verb passed to it. for example photos_path + GET combination will go to index action of photos controller while photos_path + POST combination will go to create action of photos controller

Third Column : It represent the URL the user will type in the browser

Fourth Column : It represent the controller#action combination i,e photos#index means the /photos url with GET verb will go to index action of photos controller

So. now we will see the rails way of defining routes in configuration/routes.rb file

=> Resource full routes or Resource Routing

In rails each controller is a resource and Rails being restful assume that each resource will definitely have index, show, new, create, edit, update and delete action. So rails can generate 7 url for you, by just single line below

resources :photos # it will generate the 7 routes for photos which I have already discussed above

resources :books # it will generate the 7 routes for photos which I have already discussed above

You can also generate multiple resources at the same time. So instead of two line above you can define them in single line as below

resources :photos, :books, :videos

=>  Nested Resources

It will reflect your model relation, say

class Magazine < ActiveRecord::Base
   has_many :ads

class Ad < ActiveRecord::Base
   belongs_to :magazine

This can be captured in your routes like

resources :magazines do
   resources :ads

The generated routes are:

HTTP Verb          Path                          action         named helper
GET                 /magazines/:id/ads             index         magazine_ads_path(@magazine)
GET                 /magazines/:id/ads/new         new           new_magazine_ad_path(@magazine)
POST                /magazines/:id/ads             create        magazine_ads_path(@magazine)
GET                 /magazines/:id/ads/:id         show          magazine_ad_path(@magazine, @ad)
GET                 /magazines/:id/ads/:id/edit    edit          edit_magazine_ad_path(@magazine, @ad)
PUT                 /magazines/:id/ads/:id         update        magazine_ad_path(@magazine, @ad)
DELETE              /magazines/:id/ads/:id         destroy       magazine_ad_path(@magazine, @ad)

Note:  that here you are passing magazine id in all & ads id as required wherever in normal case. Also as good rails practice avoid more then one level nesting like below as it become very cumbersome.

resources :publishers do
          resources :magazines do
                         resources :photos

=> Non-Resourceful Routes

They are basically not associated with any resource but are common route which resolve the url to a controller and action by itself

match ‘:controller(/:action(/:id))’ #since :action and :id are optional parameters, denoted by parentheses.

When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. Two of these symbols are special: :controller maps to the name of a controller in your application, and :action maps to the name of an action within that controller. For example, consider one of the default Rails routes:

match ‘:controller(/:action(/:id))’

If an incoming request of /xyz/fgh/1 is processed by this route (because it hasn’t matched any previous route in the file), then the result will be to invoke the fgh action of the xyzController, and to make the final parameter “1” available as params[:id]. This route will also route the incoming request of /xyz to xyzController#index,

Also, dynamic segment can take any thing.

match ‘:controller/:action/:id/:user_id’ #you can expand it to pass any no of params

You can’t use namespace or :module with a :controller path segment.

If you need to do this then use a constraint on :controller that matches the namespace you require. e.g:

match ‘:controller(/:action(/:id))’, :controller => /admin\/[^\/]+/

By default dynamic segments don’t accept dots – this is because the dot is used as a separator for formatted routes.If you need to use a dot within a dynamic segment add a constraint which overrides this – for example
:id => /[^\/]+/  # allows anything except a slash.

You can specify static segments when creating a route:
match ‘:controller/:action/:id/with_user/:user_id’ # here with_user is the static segment. those which do not start with : is treated as static

The params will also include any parameters from the query string. For example, with this route:
match ‘:controller/:action/:id’

An incoming path of /photos/show/1?user_id=2 will be dispatched to the show action of the Photos controller. params will be { :controller => “photos”, :action => “show”, :id => “1”, :user_id => “2” }.

You can also define other defaults in a route by supplying a hash for the :defaults option. This even applies to parameters that you do not specify as dynamic segments. For example:
match ‘photos/:id’ => ‘photos#show’, :defaults => { :format => ‘jpg’ }

Rails would match photos/12 to the show action of PhotosController, and set params[:format] to “jpg”.

=> Naming Routes or Named Routes

In the above case of non resourceful routes we are specifying the controller and action name in the url itself  by using match keyword.Let us take another example of non resourceful routes.

match “sessions/destroy” # it will try to take the user to destroy action of session controller

what if we want that the user type “/exit” in browser and he is taken to destroy action of session controller . You can further specify any specify name for any route using the :as option. This is called a named routes. see the example below

match ‘exit’ => ‘sessions#destroy’, :as => :logout

This will create logout_path and logout_url as named helpers in your application. Calling logout_path will return /exit

You can further add, various options to a named routes

=> HTTP Verb Constraints

You can use the :via option to constrain the request to one or more HTTP methods:
match ‘photos/show’ => ‘photos#show’, :via => :get

There is a shorthand version of this as well:
get ‘photos/show’

You can also permit more than one verb to a single route:
match ‘photos/show’ => ‘photos#show’, :via => [:get, :post]

=> Segment constraint
You can use the :constraints option to enforce a format for a dynamic segment:

match ‘photos/:id’ => ‘photos#show’, :constraints => { :id => /[A-Z]\d{5}/ }

This route would match paths such as /photos/A12345. You can more succinctly express the same route this way:
match ‘photos/:id’ => ‘photos#show’, :id => /[A-Z]\d{5}/

:constraints takes regular expressions with the restriction that regexp anchors can’t be used.
For example, the following route will not work:
match ‘/:id’ => ‘posts#show’, :constraints => {:id => /^\d/}

However, note that you don’t need to use anchors because all routes are anchored at the start.

For example, the following routes would allow for posts with to_param values like 1-hello-world that always begin with a number and users with to_param values like david that never begin with a number to share the root namespace:

match ‘/:id’ => ‘posts#show’, :constraints => { :id => /\d.+/ }
match ‘/:username’ => ‘users#show’

=> Request-Based Constraints

You can also constrain a route based on any method on the Request object that returns a String.

You specify a request-based constraint the same way that you specify a segment constraint:
match “photos”, :constraints => {:subdomain => “admin”}

You can also specify constraints in a block form:

namespace :admin do
      constraints :subdomain => "admin" do
             resources :photos

=>Advanced Constraints

If you have a more advanced constraint, you can provide an object that responds to matches? that Rails should use. Let’s say you wanted to route all users on a blacklist to the BlacklistController.

You could do:

class BlacklistConstraint
    def initialize
       @ips = Blacklist.retrieve_ips

    def matches?(request)

Now, you can pass the object of the above class in the routes

TwitterClone::Application.routes.draw do
   match "*path" => "blacklist#index", :constraints =>

=> Member route & collection route
You can create, any other route apart from the default restful action in a controller Use member if you do not need to pass id to controller action

resources :photos do
    member do
         get 'preview'
         put 'adjust_size'

This will recognize /photos/1/preview with GET, and route to the preview action of PhotosController. It will also create the preview_photo_url(@photo) and preview_photo_path(@photo) helpers.Note that you have to pass the id of photo

Within the block of member routes, each route name specifies the HTTP verb that it will recognize. You can use get, put, post, or delete here. If you don’t have multiple member routes, you can also pass :on to a route, eliminating the block:

resources :photos do
   get 'preview', :on => :member

To add a route to the collection:

resources :photos do
     collection do
            get 'search'

This will enable Rails to recognize paths such as /photos/search with GET, and route to the search action of PhotosController. It will also create the search_photos_url and search_photos_path route helpers.

Just as with member routes, you can pass :on to a route:

resources :photos do
   get 'search', :on => :collection

Note that, in collection routes we do not pass an ID, basically it is used for action which is going to operate on collection say all photos rather than the individual as in case of preview member of photo, as through id we need to find preview of which photo.

=> Controller Namespacing
Sometime you want to group a set of controller within one folder for example you may want to put all the  admin controller  in admin folder within the controller folder. this is called controller namespacing. all the controller within this admin folder have admin::name_of_controller format

Case 1: the default namespacing

namespace :admin do
    resources :posts, comments

It will generate routes like

HTTP Verb               Path                    action                 named helper
GET                    /admin/posts             index                  admin_posts_path
GET                    /admin/posts/new         new                    new_admin_post_path
POST                   /admin/posts             create                 admin_posts_path
GET                    /admin/posts/:id         show                   admin_post_path(:id)
GET                    /admin/posts/:id/edit    edit                   edit_admin_post_path(:id)
PUT                    /admin/posts/:id         update                 admin_post_path(:id)
DELETE                 /admin/posts/:id         destroy                admin_post_path(:id)

So not much difference, exactly same as normal case except routes are prefixed by admin, the name space

case 2 : If you want to route /posts (without the prefix /admin) to Admin::PostsController, you could use

scope :module => "admin" do
     resources :posts, comments

or, for a single case (it means one statement in one line)

resources :posts, :module => "admin"

It will generate named helper exactly as above but url will not have admin/ prefix

Case 3: You want to namespace the routes only, to say that you do not placed posts within admin folder i,e it is normal controller without any admin:: prefix or to say it is in admin folder but do not have that prefix but basically you want to draw your routes as above

i,e If you want to route /admin/posts to PostsController (without the Admin:: module prefix), you could use

scope "/admin" do
   resources :posts, :comments

or, for a single case

resources :posts, :path => "/admin/posts"

It will generate routes same as above but name helper will not have admin prefix
=> Route Globbing

Route globbing is a way to specify that a particular parameter should be matched to all the remaining parts of a route. For example

match ‘photos/*other’ => ‘photos#unknown’

This route would match photos/12 or /photos/long/path/to/12, setting params[:other] to “12” or “long/path/to/12”.

Wildcard segments can occur anywhere in a route. For example,

match ‘books/*section/:title’ => ‘books#show’

would match books/some/section/last-words-a-memoir with params[:section] equals “some/section”, and params[:title] equals “last-words-a-memoir”.

Technically a route can have even more than one wildcard segment. The matcher assigns segments to parameters in an intuitive way. For example,

match ‘*a/foo/*b’ => ‘test#index’

Starting from Rails 3.1, wildcard routes will always match the optional format segment by default.For example if you have this route:

match ‘*pages’ => ‘pages#show’

By requesting “/foo/bar.json”, your params[:pages] will be equals to “foo/bar” with the request format of JSON. If you want the old 3.0.x behavior back, you could supply :format => false like this:

match ‘*pages’ => ‘pages#show’, :format => false

If you want to make the format segment mandatory, so it cannot be omitted, you can supply :format => true like this:

=> Routing to Rack Applications

Instead of a String, like “posts#index”, which corresponds to the index action in the PostsController, you can specify any Rack application as the endpoint for a matcher.

match “/application.js” => Sprockets

As long as Sprockets responds to call and returns a [status, headers, body], the router won’t know the difference between the Rack application and an action.

For the curious, “posts#index” actually expands out to PostsController.action(:index), which returns a valid Rack application.

=> Using root

You can specify what Rails should route “/” to with the root method:
root :to => ‘pages#main’

You should put the root route at the top of the file, because it is the most popular route and should be matched first. You also need to delete the public/index.html file for the root route to take effect.

Referance :

Author: arunyadav4u

over 7 years experience in web development with Ruby on Rails.Involved in all stage of development lifecycle : requirement gathering, planing, coding, deployment & Knowledge transfer. I can adept to any situation, mixup very easily with people & can be a great friend.

One thought on “routes in rails

  1. Saved tons of my time. Really a great tutorial. Thanks

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s