Ruby on Rails: Beginner's guide to Routing

Shreyansh GuptaShreyansh Gupta
5 min read

In this article, we'll cover the basic techniques that are provided by Ruby on Rails to configure routes.

Set up routing

To set up the routing, add the following configuration code to config/routes.rb.

Rails.application.routes.draw do
  # Define routes here ...

  # Wildcard
  get "/*unmatched", to: "not_found#error"
  # root_path
  root to: "home#welcome"
end

Whenever a request is received, all the routes configured here will be matched sequentially until a match is found. We can configure a root route for requests made to /. We can also configure routes with wildcard to match requests to any unspecified URLs. Make sure to configure the wildcard routes at the bottom of the file.

Parts of a route configuration

There are broadly 4 parts to any given route in Ruby on Rails -

  • Method

  • URL

  • Module, controller and action

  • Named route helper

We can explicitly define each part while defining a route. We can also use one of the different Rails helpers to auto-generate multiple routes. These auto-generated routes will auto configure the different parts for every route as per the Rails conventions. However, we do have the flexibility to override any default behavior as per our requirements.

Resourceful routes

Let us define some CRUD routes for different actions within the UsersController.

Rails.application.routes.draw do
  # Helper - users_path, users_url
  post "/users", to: "users#create", as: :users  
  get "/users", to: "users#index", as: :users

  # Helper - user_path(:id), user_url(:id)
  delete "/users/:id", to: "users#destroy", as: :user
  put "/users/:id", to: "users#update", as: :user
end

The parameters specified in the dynamic routes are available using the params object in the controller. e.g. params[:id].

Now, if we want to define routes for all actions, we can use resources.

Rails.application.routes.draw do
  resources :users
end

It generates 7 routes. Check out the generated routes in the table below.

HTTP VerbURLController#actionHelper
GET/usersusers#indexusers_path
GET/users/:idusers#showuser_path(:id)
POST/usersusers#createusers_path
GET/users/newusers#newnew_user_path
GET/users/:id/editusers#editedit_user_path(:id)
PUT/users/:idusers#updateuser_path(:id)
DELETE/users/:idusers#destroyuser_path(:id)

We can limit the routes that are generated using the only: and except: options.

We also have a resource helper to generate routes for singular resource. This helper does not generate the index route. For the dynamic routes, :id is not included in the params because we do not expect multiple of these records to be in existence. You can check out the mapping in the Rails guides for singular resource.

e.g. It could be used to generate routes for user profile.

Nested routes

To generate nested routes, we again need to configure multiple parts for the enclosing route.

  • Path

  • Module

  • Named route helper prefix

We will not configure method. It will be specified on the individual nested routes.

Let us configure users to be nested.

Rails.application.routes.draw do
  # Controller - Admin::UsersController
  # URL - /users
  # Helpers - Same as if scope was not used
  scope module: :admin do
    resources :users
  end

  # Controller - UsersController
  # URL - /admin/users
  # Helpers - Same as if scope was not used
  scope "/admin" do
    resources :users
  end

  # Controller - UsersController
  # URL - /admin/users
  # Helpers - admin_*, new_admin_*, edit_admin_*
  scope "/admin", as: "admin" do
    resources :users
  end

  # Controller - Admin::UsersController
  # URL - /admin/users
  # Helpers - admin_*, new_admin_*, edit_admin_*
  namespace :admin do
    resources :users
  end
end

We can also nest a resource within another resource.

Rails.application.routes.draw do
  # Controller - UsersController
  # URL - /admins/:admin_id/*
  # Helpers - admin_*, new_admin_*, edit_admin_*
  resources :admins do
    resources :users
  end
end

Tip! We can also use parametric routes with scope such as /admin/:id.

Shallow nesting

To limit the nesting, we can specify the shallow option. This will nest only the collection routes. The member routes will be shallow.

Rails.application.routes.draw do
  # Collection routes are nested - index, new, create
  # Member routes are shallow - show, edit, update, destroy
  resources :admins do
    resources :users, shallow: true
  end

  # All nested routes are shallow
  resources :admins, shallow: true do
    resources :users
    resources :books
    # ...
  end

  # ======== Customize shallow routes =========

  # All member URLs are prefixed with /secret
  scope shallow_path: "secret" do
    resources :admins do
      resources :users, shallow: true
    end
  end

  # All member helpers are prefixed with
  # secret_*, new_secret_* or edit_secret_*
  scope shallow_prefix: "secret" do
    resources :admins do
      resources :users, shallow: true
    end
  end
end

Adding more RESTful routes

We can add custom routes as shown.

Rails.application.routes.draw do
  resources :users do
    # Controller - UsersController#profile
    # URL - /users/:user_id/profile
    # Helper - user_profile_path, user_profile_url
    get "profile"

    # Controller - UsersController#profile
    # URL - /users/:id/profile
    # Helper - profile_user_path, profile_user_url
    member do
      get "profile"
    end

    # Controller - UsersController#search
    # URL - /users/searcg
    # Helper - search_users_path, search_users_url
    collection do
      get "search"
    end
  end
end

Match multiple methods to the same action

The following configuration will match both GET and POST methods to the same action. However, writing to the database on a GET request is not recommended due to security reasons.

Rails.application.routes.draw do
  match "/", to: 'home#index', via: [:get, :post]

  # Route all methods to the same action
  match "/", to: 'home#index', via: :all
end

Redirects

We can set up redirects as shown.

Rails.application.routes.draw do
  # ...

  # Notice how the dynamic segment is used in the redirection
  get "/:name", to: redirect("/new_route/%{name}")
end

References

To dig deeper into the details, check out the routing section of Rails guides.

0
Subscribe to my newsletter

Read articles from Shreyansh Gupta directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shreyansh Gupta
Shreyansh Gupta