June 7, 2021
•Last updated November 5, 2023
Ruby on Rails Routing
Ruby on Rails and its routing capabilities make creating new resources and URL structures a breeze. This guide is a walk-through of some use cases for routing with the framework.
Why routing?
A strength of any web application framework is to lift a lot of the load for you. Assuming there are conventions to uphold can save teams loads of time when adding and shipping new features.
Rather than craft URL schemes and invoke ways to pass in property ids you can leverage the internals of the framework to get the job done in a few lines of code or less.
Routing with Rails
There are virtually endless ways to declare new routing schemes in a Ruby on Rails application but my hope is this guide sheds some light on the basics. Be sure to leverage the documentation for the most up-to-date and accurate depictions of all that is in this article/video.
How can I view what routes my application has?
There are a couple of ways to view your existing routing.
Assuming you have your
rails server
running locally you can visitlocalhost:3000/rails/info/routes
. This displays a list of which you can filter through to see all the available options. As an application scales so does this list so it might be tough to navigate longer term.If you prefer the console you can also run
rails routes
within your project's root folder. Doing so displays the same list as the example before though again it can get tough to read as the application scales.
Root route
A great place to start is known as the "root" route. This for all things considered is your app's "homepage". Whenever someone visits your website or you boot up your local server, this is the first place the app will load.
Creating a root route requires a controller and an action on that controller to work. Additionally, to render content you would need a view template as well.
Example:
root to: "home#index"
Here I'm rooting to the home_controller.rb
and the index
action/method inside that controller. Rails would look for the view in app/views/home/index.html.erb
to resolve the HTML/ERB that could be rendered here.
Resources (RESTful)
Ruby on Rails follows the RESTful pattern by default. Other technologies like GraphQL exist today to alter this contstruct but in the wild, I would bet most APIs are still following REST conventions.
If you're new to REST it stands for Representational state transfer. The goal of REST is to increase at scale across any size application all while being fast and efficient. This ultimately is a fancy way to explain the different forms of HTTP requests an API can hook into.
In rails, a resource
stands for something like a basic object or model. When you define this it assumes you have a table in the database with a similar naming convention.
posts_table
in your database might correspond to resources :posts
for example.
resources :posts
Here's a basic example of the full RESTful solution condensed into one line.
resources :posts, :categories, :tags
You can comma separate multiple resources if you have many.
Taking our first example you could define it and visit localhost:3000/rails/info/routes or run rails routes
and see something similar.
# GET /posts - posts#index - display a list of all posts
# GET /posts/new - posts#new - return an HTML form for creating a new posts
# POST /posts - posts#create - create a new posts
# GET /posts/:id - posts#show - display a specific posts
# GET /posts/:id/edit - posts#edit - return an HTML form for editing a posts
# PATCH/PUT /posts/:id - posts#update - update a specific posts
# DELETE /posts/:id - posts#destroy - delete a specific posts
Examples:
Putting this routing to use in views and helpers
posts_path
returns/posts
new_post_path
returns/posts/new
edit_posts_path(:id)
returns/posts/:id/edit
- -
(edit_post_path(10)
returnsposts/10/edit
) post_path(:id)
returns/posts/:id
(for instance,post_path(10)
returns/posts/10
)
Resource (RESTful but singular)
Sometimes, you have a resource that clients always look up without referencing an ID. So intead of /profile/1
it can be just /profile
Rails controller actions would include: show
, new
, create
, edit
, update
,destroy
# GET /profile/new - profiles#new - return an HTML form for creating the profile
# POST /profile - profiles#create - create the new profile
# GET /profile - profiles#show - display the one and only profile resource
# GET /profile/edit - profiles#edit - return an HTML form for editing the profile
# PATCH/PUT /profile - profiles#update - update the one and only profile resource
# DELETE /profile - profiles#destroy - delete the profile resource
Namespacing
If you want a specific path for a resource you can "contain" it inside a namespace. This is common for private or admin areas of an app or places you'd like more control over the URL schema.
namespace :admin do
resources :articles
end
Results in
# GET /admin/articles - admin/articles#index - admin_articles_path
# GET /admin/articles/new - admin/articles#new - new_admin_article_path
# POST /admin/articles - admin/articles#create - admin_articles_path
# GET /admin/articles/:id - admin/articles#show - admin_article_path(:id)
# GET /admin/articles/:id/edit - admin/articles#edit - edit_admin_article_path(:id)
# PATCH/PUT /admin/articles/:id - admin/articles#update - admin_article_path(:id)
# DELETE /admin/articles/:id - admin/articles#destroy - admin_article_path(:id)
For even more organization you can add ruby modules to the mix to move your controller in the admin space so your routing and controllers follow the same encapsulation patterns.
scope module 'admin' do
resources :articles
end
# or
resources :articles, module: :admin
Your controller would then move to a module or in app/controllers/admin/articles_controller.rb
instead of just app/controllers/
.
Inside the controller you would write the class a bit differently to compensate
Admin::ArticlesController < ApplicationController
...
end
Nesting routes
Simply nest like you would with a ruby block. It's recommended to never nest 3 levels deep although it's possible.
resources :categories
resources :posts
end
Example output and URL schemes:
# GET /categories/:category_id/posts
# posts#index
# display a list of all posts for a specific category
# category_posts_path(@category) # requires an instance of Category
# ----
# GET /categories/:category_id/posts/new
# posts#new
# return an HTML form for creating a new post belonging to a specific category
# new_category_post_path(@category) # requires an instance of Category
# ----
# POST /categories/:category_id/posts
# posts#create
# create a new post belonging to a specific category
# ----
# GET /categories/:category_id/posts/:id
# posts#show
# display a specific post belonging to a specific category
# category_post_path(@category, @post) # requires an instance of Category and Post
# ----
# GET /categories/:category_id/posts/:id/edit
# posts#edit
# return an HTML form for editing an post belonging to a specific category
# edit_category_post_path(@category, @post) # requires an instance of Category and Post
# ----
# PATCH/PUT /categories/:category_id/posts/:id
# posts#update
# update a specific post belonging to a specific category
# ----
# DELETE /categories/:category_id/posts/:id
# posts#destroy
# delete a specific post belonging to a specific category
# category_post_path(@category, @post), method: :delete # requires an instance of Category and Post
Routing Concerns
Routing concerns allow you to declare common routes that can be reused inside other resources and routes.
concern :commentable do
resources :comments
end
# or
resources :comments, concerns: :commentable # this can be an array too i.e. [:commentable, :taggable]
# the above is equivelant to
resources :messages do
resources :comments
end
resources :articles do
resources :comments
resources :taggable, only: :index
end
Adding more RESTful actions
You can extend the default resources and resource to include additional restful and non-restful routing.
resources :photos do
member do
get 'preview'
end
end
This will recognize /photos/1/preview
with a GET
HTTP request, and route to the preview
action of PhotosController
, with the resource id value passed in params[:id]
. It will also create the preview_photo_url
and preview_photo_path
helpers automatically 🏄.
Adding Collection Routes
If you need a collection style of response you can add that much like the member
block. Swap member
with collection
and you're all set.
resources :photos do
collection do
get 'search'
end
end
Non-RESTful routing
A quick way to add routing for virtually any one-off path you need
get 'my/:id', to: 'users#dashboard'
returns my/1
Defaults
Only want to return JSON
or some form of media? (jpg
, xml
, etc...)
get 'users/:id', to: 'users#show', defaults: { format: 'json' }
Here Rails would match users/1
to the show
action of UsersController
, and set params[:format]
to json
.
Naming routes
You can name a route whatever you please even if it doesn't match controller or path logic. Use the as a method to pass a symbol of the name you wish to use.
get 'exit', to: 'sessions#destroy', as: :logout
If you want to override parts of a resource you can by passing a named route first.
get ':username', to: 'users#show', as: :user
resources :users
This will define a user_path method that will be available in controllers, helpers, and views that will go to a route such as /bob
. Inside the show
action of UsersController
, params[:username]
will contain the username for the user. Change
:username
in the route definition if you do not want your parameter name to be :username
.
Part 2 coming soon
With the basics of routing out of the way I hope I helped shed some light on how the conventional routing patterns work inside Ruby on Rails. It gets more advanced from here. If you need subdomains, bot-detection/mitigation, alternative languages, and more look for another part explaining those in more detail to come.
Be sure to subscribe to my newsletter or YouTube channel if you haven't already. This helps me keep going and bring you the best content I can!
Categories
Collection
Part of the Ruby on Rails collection
Products and courses
-
Hello Hotwire
A course on Hotwire + Ruby on Rails.
-
Hello Rails
A course for newcomers to Ruby on Rails.
-
Rails UI
UI templates and components for Rails.