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
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
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
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
Albums. Let's update routes.rb to handle this relationship:
Rails.application.routes.draw do resources :albums do resources :songs end end
do ... end to
resources :albums to create a block and then we nest
resources :songs inside of that.
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
:only. For example, if we didn't want users to destroy
Songs, we might do this:
... resources :songs, except: [:destroy] ...
If we wanted users only to be able to see a list of
Songs 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