Ruby on Rails: Advanced routing
In this article, we’ll cover some advance configurations that Ruby on Rails provides us for routing.
Routing concerns
Concerns allow us to create reusable routes that can be used inside other resources and routes.
Rails.application.routes.draw do
concern :accountable do
resources :accounts
end
concern :profilable do
resources :profiles
end
resources :users, concerns: :accountable
resources :customers, concerns: [:accountable, :profilable]
# The above code is equivalent to the following
resources :users do
resources :accounts
end
resources :customers do
resources :accounts
resources :profiles
end
end
Optional parameters
We can have optional parameters in the URLs. Such URLs can be defined as shown below.
Rails.application.routes.draw do
# Matches both - /users/1 and /users
get "/users(/:id)", to: "users#show"
end
Defining defaults
We can specify default values in a route as shown below.
Rails.application.routes.draw do
# Method 1
get "/users/:id", to: "users#show", defaults: { format: :json }
# Method 2
defaults format: :json do
get "/users/:id", to: "users#show"
end
end
Segment Constraints
We can enforce a format constraint for a dynamic segment within a route as shown below. A dynamic segment would be the dynamic part of the URL such as :id
and :username
in the example shown below.
Rails.application.routes.draw do
# Only a URL with a 5 digit ID is matched to this route.
get "/users/:id", to: "users#show", constraints: { id: /\d{5}/ }
# Only a URL with a 5 alphabet uppercase username is matched to this route.
get "/users/:username", to: "users#show", constraints: { username: /[A-Z]{5}/ }
end
Request based constraints
We can also add a constraint based on any property on the Request object that returns a string.
Rails.application.routes.draw do
get "/users/:id", to: "users#show", constraints: { subdomain: "admin" }
# OR
get "/users/:id", to: "users#show", constraints: lambda { |req| req.subdomain == "admin" }
end
Note that to apply a constraint on the format
of the request (req.format
), we must pass in a lambda
. A format
constraint specified using a Hash
will also match requests where no format
is specified. This is because format
is an optional parameter on every request. So to only match JSON
requests, we must pass in the following -
..., constraints: lambda { |req| req.format == :json }
We can also apply more advanced constraints as demonstrated in the Rails guide.
Customizing the routes
We can specify the controller to be used for generating the routes as shown below.
Rails.application.routes.draw do
# UsersController
resources :users, controller: "users"
# Admin::UsersController
resources :users, controller: "admin/users"
end
We can also update the param name for the generated routes.
Rails.application.routes.draw do
# /users/:identifier
resources :users, param: :identifier
end
Breaking up a large routes file
To break up a large routes file, we can use the draw
method. It will search for a filename corresponding to the param passed within the /config/routes/*
directory and sub-directories.
# /config/routes.rb
Rails.application.routes.draw do
draw(:admin)
end
# /config/routes/admin.rb
namespace :admin do
# admin routes ...
end
CLI
Rails also has a powerful CLI utility that allows us to view the routes within the console. Check out the Rails guides for usage.
References
To dig deeper, 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