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 following seven operations.
These seven actions collectively are known as RESTful representation of the book.
We can see that in the all the above seven cases sentences starts with HTTP verb GET
or POST
except
for item number 6 & 7.
In the item number 6 we are trying to update a particular book.
We can use POST
to update the record but Rails has decided to support both
PUT
and
PATCH
for updating.
Let's write routes for all the seven actions.
Let's assume that we have a controller named BooksController
.
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 'book/edit', to: "books#edit"
7 put 'book/update', to: "books#update"
8 delete 'books/:id', to: "books#destroy"
9end
The BooksController
would look something like this.
1class BooksController < ApplicationController
2 def index
3 end
4
5 def show
6 end
7
8 def new
9 end
10
11 def edit
12 end
13
14 def create
15 end
16
17 def update
18 end
19
20 def destroy
21 end
22end
Writing all those seven lines of code in routes file time and again
for each item gets repetitive.
Rails has put all that under the umbrella term of resources
.
Here is a version without using resources.
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 'book/edit', to: "books#edit"
7 put 'book/update', to: "books#update"
8 delete 'books/:id', to: "books#destroy"
9end
Here is how the code would look if we use resources. Note that both the code do almost same thing.
1Rails.application.routes.draw do
2 # delete all the lines and add just the following line
3 resources :books
4end
Think of resources
as a shortcut for not typing all that code.
If we look at
mapper.rb
code in Rails codebase we can see all the seven methods listed there.
Now let's see what the routes look like when we are using resources
.
1bundle exec rake routes
Prefix | VERB | URI Pattern | Controller#Action | Used for |
---|---|---|---|---|
books | GET | /books | books#index | List books |
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 |
In the above table we see columns "Prefix" which we will discuss in a different chapter.
Sometimes we do not need all the seven routes. For example let's say that in our application we do not have capability to delete any book. If a user sends a DELETE request then we should not send that request to any controller. In order to do that we need to tell Rails Routing to not to have any routing for DELETE verb.
1resources :books, except: [:destroy]
Here is another example.
1resources :books, only: [:index, :show]
In the above case user can only see list of books and can get information about a book. User can't create, edit or delete a book.
Let's put what we have learned in action. Execute following commands on terminal.
1bundle exec rails generate scaffold articles name:string desc:text
2bundle exec rails db:migrate
3bundle exec rails server
Now visit http://localhost:3000/rails/info/routes. We will see a bunch of routes. We can also see these routes by executing following command.
1bundle exec rake routes
The output should look familiar.
So far we have been using resources
.
Rails also provides singular version of it called resource
.
Rails recommends us to use singular resource when we do not have an identifier.
For example typically the url for profile page is /profile
and not /profile/495
.
In such cases we do not need certain routes.
Let's see it in action.
Open config/routes.rb
and add following line.
1resource :profile
Now let's see the routes that are generated.
1bundle exec rake routes
Prefix | VERB | URI Pattern | Controller#Action |
---|---|---|---|
new_profile | GET | /profile/new | profiles#new |
edit_profile | GET | /profile/edit | profiles#edit |
profile | GET | /profile | profiles#show |
PATCH | /profile | profiles#update | |
PUT | /profile | profiles#update | |
DELETE | /profile | profiles#destroy | |
POST | /profile | profiles#create |
Notice that the URL pattern is using singular style.
URLs are /profile/new
and not /profiles/new
.
However the controller name is still plural.
This was subject of a great debate within the Rails community.
However the community has decided to keep the controller name
plural whether it is a singular resource or a multiple resource.
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 :photo and resources :photos creates both singular and plural routes that map to the same controller (PhotosController).
Notice that for the show
action the corresponding URL is just /profile
.
No identifier is needed.
Same for deleting the profile and for creating and updating the profile.
Finally there is no index
action since here we are talking about a singular
resource.
Another common usage of singular resource is when we are dealing with login operation. When user logs in then we need to maintain a session. For each logged in user there could be only one session.
1resource :session, only: [:new, :create, :destroy]
Controller could look like this.
1class SessionsController < ApplicationController
2 def new
3 end
4
5 def create
6 end
7
8 def destroy
9 end
10end
We are not going to check all these changes.
1git clean -fd