Ruby on Rails: Beginner's guide to Routing
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 Verb | URL | Controller#action | Helper |
GET | /users | users#index | users_path |
GET | /users/:id | users#show | user_path(:id) |
POST | /users | users#create | users_path |
GET | /users/new | users#new | new_user_path |
GET | /users/:id/edit | users#edit | edit_user_path(:id) |
PUT | /users/:id | users#update | user_path(:id) |
DELETE | /users/:id | users#destroy | user_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.
Subscribe to my newsletter
Read articles from Shreyansh Gupta directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by