Let's say that we have a library full of books and we need to build an application to manage these books. Typically we need to perform the following seven operations.
- GET the list of all books.
- GET detailed information about a particular book.
- Click on "Add a new book" and GET a form in response.
- POST the values from the form to create a new book.
- GET the form with an existing book's data prepopulated so that the user can edit the information about the book.
- UPDATE the system with the edited data that was just submitted.
- DELETE the book.
These seven actions collectively are known as RESTful representations of the
book. We can see that in all the above seven cases, sentences contain the HTTP
POST except for operation numbers 6 and 7.
In operation number 6, we are trying to update a particular book. It is possible
to use the
POST method for updating the records. But we will be following the
Rails' standards and will use
The routes for all the seven actions will look like this:
1Rails.application.routes.draw do 2 get '/books', to: "books#index" 3 get '/books/:id', to: "books#show" 4 get '/books/new', to: "books#new" 5 post '/books', to: "books#create" 6 get '/books/:id/edit', to: "books#edit" 7 put '/books/:id', to: "books#update" 8 delete '/books/:id', to: "books#destroy" 9end
Writing all those seven lines of code in the routes file time and again for each
item gets repetitive. Rails has put all that under the umbrella term of
If we use
resources instead of manually specifying all routes, this is how the
routes definition will look like:
1Rails.application.routes.draw do 2 resources :books 3end
resources as a shortcut for not typing all that code. Looking into
file from Rails codebase, we can see that all the seven methods are listed
Rails provides a Rake task to list all the routes.
1bundle exec rails routes
As we discussed that one single
resources :books is responsible for generating
these seven routes.
|Prefix||VERB||URI Pattern||Controller#Action||Used for|
|POST||/books||books#create||Create a book|
|new_book||GET||/books/new||books#new||Form for a new book|
|edit_book||GET||/books/:id||books#edit||Form for editing book|
|book||GET||/books/:id||books#show||Show info about book|
|PATCH||/books/:id||books#update||Update info about book|
|PUT||/books/:id||books#update||Update info about book|
|DELETE||/books/:id||books#destroy||Delete info about book|
If we visit visit http://localhost:3000/rails/info/routes then also we can see all the routes.
Using only and except to be selective
Sometimes we do not need all the seven routes. For example, let's say that in
our application, we don't need to allow users to delete any book. In that case,
even if a user sends a DELETE request, we don't want the
destroy action to be
In order to do that, we need to tell Rails Routing not to have any routing for DELETE verb:
1resources :books, except: [:destroy]
Here is another example:
1resources :books, only: [:index, :show]
In this case, only
show actions are added to routing. That is, a
user can see the list of books and can get details about a book. But they can't
create, edit or delete a book.
Difference between singular resource and resources in Rails routes
So far, we have been using
resources. Rails also provides a singular version
of it called
Rails recommends us to use singular resource when we do not have an identifier.
For example, the URL for the profile page is, typically,
/profile and not
/profile/495. In such cases, we do not need certain routes.
For example, if we define a resource like this in
The routes generated by singular resource will be:
Notice that the URL pattern is using the singular style. URLs are
However, the controller name is still plural. This was a subject of great debate within the Rails community. The community decided to keep the controller name plural for both singular and multiple resources.
Here is an explanation from the Rails official guide:
Because you might want to use the same controller for a singular route (
/account) and a plural route (
/accounts/45), singular resources map to plural controllers. So that, for example, resource
:photoscreates both singular and plural routes that map to the same controller (
Notice that for the
show action, the corresponding URL is just
identifier is needed. The same is true for creating, updating, and deleting the
In this case, for all these actions, we will be performing the operations on the currently logged-in user's data. Therefore we don't need an identifier for those actions.
Finally, there is no
index action since here we are talking about a singular
Another common usage of the singular resource is when we are dealing with login operations. When a user logs in, we need to maintain a session. For each logged-in user, there could be only one session.
In that case, our routes definition will look like this:
1resource :session, only: [:new, :create, :destroy]
Controller could look like this:
1class SessionsController < ApplicationController 2 def new 3 # logic 4 end 5 6 def create 7 # logic 8 end 9 10 def destroy 11 # logic 12 end 13end
There shouldn't be any changes to the application in this chapter. So let us clean up any accidental changes.
1git clean -fd