In a Rails application, all of our routes are stored in config/routes.rb. For the most part, we won't be using the config much other than this file.
Let's make an update to routes.rb to include full CRUD routing for albums:
Rails.application.routes.draw do
resources :albums
end
The resources
keyword is the Rails convention for adding a group of routes. When we specify resources :<class name here>
, Rails will automatically create all the routes we need to add CRUD functionality for that class.
Note that we must use resources
, not resource
. If we were to say resource :albums
instead, we will get only six of the routes included below. albums#index
would be omitted, which we don't want. This typo is a common error for beginners.
We can take a look at the routes our application has by typing in rake routes
in the terminal:
Prefix Verb URI Pattern Controller#Action
albums GET /albums(.:format) albums#index
POST /albums(.:format) albums#create
new_album GET /albums/new(.:format) albums#new
edit_album GET /albums/:id/edit(.:format) albums#edit
album GET /albums/:id(.:format) albums#show
PATCH /albums/:id(.:format) albums#update
PUT /albums/:id(.:format) albums#update
DELETE /albums/:id(.:format) albums#destroy
# ActiveStorage routes omitted for now.
Rails has automatically generated seven RESTfully named routes for us. They correspond to all of the routes we need for CRUD:
Each route has a prefix, verb, URI pattern and controller action.
The prefix is a "helper path" that determines how we can link to the page in a Rails application. For example, if we wanted to create a link for the new album page, we could use the new_album_path
, which combines the prefix new_album
with _path
.
The verb is the HTTP verb associated with the route's action. We covered this in detail in the last course section.
The URI pattern is the path for the route. We covered this in the last course section as well. The (:format)
at the end of the route just tells us that the route can return different data formats such as images.
The controller action specifies which controller action will handle that particular route. We will cover controllers in more detail in the next lesson.
Let's break this down into an actual example. Let's say a user clicks on a link for creating a new album. Our view would utilize the new_album_path
(which includes the prefix). Our application would then GET
(the route action) the new album form page. This page is at /albums/new (the URI pattern), which is RESTfully named. Finally, the controller at albums#new
(the controller action) will run any necessary code and determine what content will be served to the user.
rake routes
provides a lot of helpful information, especially as our routes become more complicated.
One last note: we've omitted the last five routes that are provided for ActiveStorage. ActiveStorage allows us to associate file uploads with a record but we won't worry about that until the next course section.
We can create any number of grouped CRUD routes using the resources
keyword. We can also nest routes, which we will want to do for our association between Song
s and Album
s. Let's update routes.rb to handle this relationship:
Rails.application.routes.draw do
resources :albums do
resources :songs
end
end
We add do ... end
to resources :albums
to create a block and then we nest resources :songs
inside of that.
Let's run rake routes
again:
Prefix Verb URI Pattern Controller#Action
album_songs GET /albums/:album_id/songs(.:format) songs#index
POST /albums/:album_id/songs(.:format) songs#create
new_album_song GET /albums/:album_id/songs/new(.:format) songs#new
edit_album_song GET /albums/:album_id/songs/:id/edit(.:format) songs#edit
album_song GET /albums/:album_id/songs/:id(.:format) songs#show
PATCH /albums/:album_id/songs/:id(.:format) songs#update
PUT /albums/:album_id/songs/:id(.:format) songs#update
DELETE /albums/:album_id/songs/:id(.:format) songs#destroy
albums GET /albums(.:format) albums#index
POST /albums(.:format) albums#create
new_album GET /albums/new(.:format) albums#new
edit_album GET /albums/:id/edit(.:format) albums#edit
album GET /albums/:id(.:format) albums#show
PATCH /albums/:id(.:format) albums#update
PUT /albums/:id(.:format) albums#update
DELETE /albums/:id(.:format)
# ActiveStorage routes excluded.
Now we have fourteen routes (not including ActiveStorage routes). Because songs are nested within albums, all routes related to songs reflect that nesting. For instance, to get all songs belonging to an album, we'd have the following prefix: album_songs
. That would route to /albums/:album_id/songs
, which would return the index
action in a songs controller.
It's common to nest routes in one-to-many relationships. However, it's a bad practice to nest our routes any more deeply than this. For instance, the deep nesting below would be a code smell:
resources :resource1 do
resources :resource2 do
resources :resource3
end
end
Creating a root route is also very simple. For instance, if we wanted our application's home page to be the list of all albums, we could do this:
Rails.application.routes.draw do
root to: 'albums#index'
...
end
We can also specify that a group of resources should only have certain actions by using either :except
or :only
. For example, if we didn't want users to destroy Song
s, we might do this:
...
resources :songs, except: [:destroy]
...
If we wanted users only to be able to see a list of Song
s but not be able to do any other CRUD functionality, we could do this:
...
resources :songs, only: [:index]
...
We would then see the corresponding changes in rake routes
as well.
We will be using all seven routes for both albums and songs. However, if you find that you don't need all the routes in an application, they should be cleaned up. This will help communicate your intentions better to other developers.
We can also do more complex routing as well, including creating non-resourceful routes, redirects, and customizing just about every part of a route. Check out the following Rails documentation for more information. At the very least, skim through this document to get a better sense of how you can customize routes in your application. And while it is possible to create custom routes, avoid doing so for now. The conventional routes included in our application should be able to handle everything we need.
Now that we've covered the basics of routing, we're ready to take a closer look at controllers.
Lesson 9 of 34
Last updated July 14, 2022