Routing in Ruby on Rails

The last two weeks I’ve been working on a rails project for the coding bootcamp that I’m in. When switching from Sinatra (another web-application framework that works with Ruby) to Rails, it can be both amazing and frightening how much of the work that Rails takes out of your hands. One of the many differences between Sinatra and Rails is the way in which you handle your routing. Luckily for us, though different, routing in rails is fairly intuitive and powerful once you’ve figured out the basics.

While in Sinatra you handle your routing in your controllers, in Rails your routing is handled in the config/routes.rb file. Upon generating a new Rails application, that file should already contain something that looks like this

Rails.application.routes.draw doend

All of your routing will take place inside that block of code. According to to the Rails Guides :

Time to start defining some routes!

So when your application receives an HTTP request it’s going to look in your routes.rb to see which controller to direct the request to. Say you have a User model, and you link to the show page for an instance of a user, perhaps their profile page. If someone follows that link your application is going to be looking in your routes.rb for a route that looks like:

Rails.application.routes.draw do
get '/users/:id', to: 'users#show'
end

This is saying, if your application receives a get request to ‘/users:id’ where :id is the number of the user’s id, send them to the UsersController to the show method. So your UsersController might look like:

class UserController < ApplicationController    def show
end
end

And that method would determine what would happen when the link to the user’s show page is visited, most likely you would render the view for their profile page. Following with this logic the 7 RESTful routes for the UserController could be defined like:

Rails.application.routes.draw do    get '/users', to: 'users#index'
get '/users/new', to: 'users#new'
post '/users', to: 'users#create'
get '/users/:id', to: 'users#show'
get '/users/edit', to: 'users#edit'
post '/users/:id', to: 'users#update'
delete '/users/:id', to: 'users#destroy'
end

When writing our routes out this way, Rails creates a set of predetermined route helpers, these route helpers are for us to use anywhere we want to reference the url that correlates to the specified controller action. The route helpers we would be given with our users example are:

  • users_path => '/users'
  • user_path(:id) => '/users/id'
  • new_user_path => '/users/new'
  • edit_user_path(:id) => '/users/:id/edit'

You can combine these route helpers with http verbs to get your put, patch, and delete requests. For instance method: :delete, url: user_path(user.id). If you would like to change the url or the route helper, all you have to do is define your route like get '/people/:id', to: 'users#show', as: 'people' this in turn will make the route helper people_path(:id) and one would then visit the user show page by going to ‘/people/:id’ instead. Super simple, right?

It Gets Even Easier!

In Rails you can do something that’s called resource routing. With resource routing we can define all of the 7 RESTful routes with one simple macro:

Rails.application.routes.draw do  resources :usersend

But… what if you don’t need all 7 RESTful routes? That’s okay, you can still use the resources macro!

resources :users, only: [:new, :show, :index] would give us these routes:

get '/users', to: 'users#index', as: 'users'
get '/users/new', to: 'users#new', as: 'new_users'
get '/users/:id', to: 'users#show', as: 'user'

Resource routing also makes it really simple to nest routes. For example, let’s say in addition to our User model, we also have an Item mode. An Item belongs to a user, we may want to convey that through our routing. So an item show page instead of being through the url ‘/items/id’, would instead go through ‘users/:user_id/items/:id’ . It would be really tiring having to write out all of the routing for an item by hand, but with the resources macro all we need to do is:

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

This would produce all 7 RESTful routes for users, and items. This is cool, but what if you only want to nest some of your routes for item? This is still really easy to do with the resources macro:

Rails.application.routes.draw do    resources :users do
resources :items, only: [:index, :new, :create]
end
resources :items, only: [:show, :edit, :update, :destroy]end

Note: The above example is an instance of shallow routing, which is a concept of using routes with the minimal amount of information to uniquely identify the resource. A shorter way to achieve the result above is to use resources: items, shallow: true where it’s defined inside of the users resources block.

As you can see, routing in Rails is rather easy. There are still a ton of other things you can do to customize your routes and route helpers, and the Rails Guides outline them well. I highly recommend checking it out. So, what do you think? Do you prefer routing in Rails or Sinatra? At first it was a little difficult for me to wrap my head around having to define my routes and controller actions separately, but my opinion is that it’s a good separation.

--

--

Aspiring Software Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store