# Routing

# Basic Routing

The most basic Rails routes accept a URI and Controller method, providing a very simple and expressive method of defining routes and behavior without complicated routing configuration files:

get '/photos', to: 'photos#index'
1

the request is dispatched to the photos controller's index action .

  • The Default Route Files

    All Rails routes are defined in your route files, which are located in the config directory.

  • Available Route Methods

    Rails supports four different routes methods in application

    get 'uri', to: 'controller#method'
    post 'uri', to: 'controller#method'
    patch/put 'uri', to: 'controller#method'
    delete 'uri', to: 'controller#method'
    
    1
    2
    3
    4
  • CSRF Protection

    Remember, any HTML forms pointing to POSTPUTPATCH, or DELETE routes that are defined in the web routes file should include a CSRF token field. Otherwise, the request will be rejected.

    As a Rails developer, you basically get CSRF protection for free. It starts with this single line in application_controller.rb, which enables CSRF protection:

    protect_from_forgery with: :exception
    
    1

    Next, there's this single line in application.html.erb:

    <%= csrf_meta_tags %>
    
    1
  • Redirect Routes

    You can redirect any path to another path by using the [redirect](https://api.rubyonrails.org/v7.0.4/classes/ActionDispatch/Routing/Redirection.html#method-i-redirect) helper in your router:

    get '/stories', to: redirect('/articles')
    
    1

    You can also reuse dynamic segments from the match in the path to redirect to:

    get '/stories/:name', to: redirect('/articles/%{name}'
    
    1

    You can also provide a block to redirect, which receives the symbolized path parameters and the request object:

    get '/stories/:name', to: redirect { |path_params, req| "/articles/#{path_params[:name].pluralize}" }
    get '/stories', to: redirect { |path_params, req| "/articles/#{req.subdomain}" }
    
    1
    2

    Please note that default redirection is a 301 "Moved Permanently" redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible. You can use the :statusoption to change the response status:

    get '/stories/:name', to: redirect('/articles/%{name}', status: 302)
    
    1
  • The Route List

    The routes Artisan command can easily provide an overview of all of the routes that are defined by your application:

    bin/rails routes
    
    1

    You can also use the --expanded option to turn on the expanded table formatting mode.

    You can search through your routes with the grep option: -g. This outputs any routes that partially match the URL helper method name, the HTTP verb, or the URL path.

    bin/rails routes -g new_comment
    bin/rails routes -g POST
    bin/rails routes -g admin
    
    1
    2
    3

    If you only want to see the routes that map to a specific controller, there's the -c option.

    bin/rails routes -c users
    bin/rails routes -c admin/users
    bin/rails routes -c Comments
    bin/rails routes -c Articles::CommentsController
    
    1
    2
    3
    4
  • Route Globbling and Wildcard Segments

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

    get 'photos/*other', to: 'photos#unknown'
    
    1

    This route would match photos/12or /photos/long/path/to/12, setting params[:other] to "12"or "long/path/to/12". The segments prefixed with a star are called "wildcard segments".

  • Using root

    You can specify what Rails should route '/' to with the [root](https://api.rubyonrails.org/v7.0.4/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-root) method:

    root to: 'pages#main'
    root 'pages#main' # shortcut for the above
    
    1
    2

    You should put the rootroute at the top of the file, because it is the most popular route and should be matched first.

# Routes Parameters

  • Required Parameters

    Sometimes you will need to capture segments of the URI within your route. For example, you may need to capture a user's ID from the URL. You may do so by defining route parameters:

    get 'users/:id', to: 'users#display'
    
    1

    If an incoming request of /photos/1is processed by this route (because it hasn't matched any previous route in the file), then the result will be to invoke the displayaction of the PhotosController, and to make the final parameter "1"available as params[:id] . This route will also route the incoming request of /photosto PhotosController#display, since :is an optional parameter, denoted by parentheses.

    You can set up as many dynamic segments within a regular route as you like. Any segment will be available to the action as part of params.

    get 'photos/:id/:user_id', to: 'photos#show'
    
    1
  • The Query String

    The params will also include any parameters from the query string. For example, with this route:

    get 'photos/:id', to: 'photos#show'
    
    1

    An incoming path of /photos/1?user_id=2will be dispatched to the show action of the Photoscontroller. paramswill be { controller: 'photos', action: 'show', id: '1', user_id: '2' } .

  • Defining Defaults

    You can define defaults in a route by supplying a hash for the :defaultsoption. This even applies to parameters that you do not specify as dynamic segments. For example:

    get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' }
    
    
    1
    2

    You can also use a [defaults](https://api.rubyonrails.org/v7.0.4/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-defaults) block to define the defaults for multiple items:

    defaults format: :json do
      resources :photos
    end
    
    1
    2
    3
  • Regular Expression Constraints

    You can use the :constraintsoption to enforce a format for a dynamic segment:

    get 'photos/:id', to: 'photos#show', constraints: { id: /[A-Z]\d{5}/ }
    
    1
  • Named Routes

    You can specify a name for any route using the :as option:

    get 'exit', to: 'sessions#destroy', as: :logout
    
    1

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

# Resource Routing

Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. A single call to [resources](https://api.rubyonrails.org/v7.0.4/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-resources)can declare all of the necessary routes for your indexshowneweditcreateupdate, and destroyactions.

resources :photos
1

creates seven different routes in your application, all mapping to the Photos controller:

| --- | --- | --- | --- |

  • Path and URL Helper

    Creating a resourceful route will also expose a number of helpers to the controllers in your application. In the case of resources :photos:

    • photos_path returns /photos
    • new_photo_path returns /photos/new
    • edit_photo_path(:id) returns /photos/:id/edit (for instance, edit_photo_path(10) returns /photos/10/edit)
    • photo_path(:id) returns /photos/:id (for instance, photo_path(10) returns /photos/10)

    Each of these helpers has a corresponding _url helper (such as photos_url) which returns the same path prefixed with the current host, port, and path prefix.

  • Defining Multiple Resource at same time

    If you need to create routes for more than one resource, you can save a bit of typing by defining them all with a single call to resources:

    resources :photos, :books, :videos
    
    1

    This works exactly the same as:

    resources :photos
    resources :books
    resources :videos
    
    1
    2
    3

# Route Groups

  • Controllers

    You may wish to organize groups of controllers under a namespace. Most commonly, you might group a number of administrative controllers under an Admin::namespace, and place these controllers under the app/controllers/admindirectory. You can route to such a group by using a [namespace](https://api.rubyonrails.org/v7.0.4/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-namespace)block:

    namespace :admin do
      resources :articles, :comments
    end
    
    1
    2
    3

    This will create a number of routes for each of the articlesand comments  controller. For Admin::ArticlesController, Rails will create:

    | --- | --- | --- | --- |

    If instead you want to route /articles(without the prefix /admin) to Admin::ArticlesController, you can specify the module with a [scope](https://api.rubyonrails.org/v7.0.4/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-scope)  block:

  • Nested Resources

    It's common to have resources that are logically children of other resources. For example, suppose your application includes these models:

    class Magazine < ApplicationRecord
      has_many :ads
    end
    
    class Ad < ApplicationRecord
      belongs_to :magazine
    end
    
    1
    2
    3
    4
    5
    6
    7

    Nested routes allow you to capture this relationship in your routing. In this case, you could include this route declaration:

    resources :magazines do
      resources :ads
    end
    
    1
    2
    3

    In addition to the routes for magazines, this declaration will also route ads to an AdsController. The ad URLs require a magazine:

    | --- | --- | --- | --- |

    This will also create routing helpers such as magazine_ads_urland edit_magazine_ad_path . These helpers take an instance of Magazine as the first parameter (magazine_ads_url(@magazine)).

  • Routing Concerns