Routing is the process of mapping incoming requests to the appropriate controller actions. It involves defining a set of routes in the application's configuration file that specify which URLs should be handled by which controller actions. These routes can also include placeholders for dynamic data, such as IDs or usernames, which can then be accessed by the controller action.
Nested routing allows the creation of routes that are nested within another resource's routes. This means that a resource can have multiple levels of associations, and each association can be represented by a nested URL.
Consider a real-life scenario in which we have two resources in our application—authors
and books
. Each book is associated with an author, and each author can have multiple books. To set up nested routing, we can define a route for books
that is nested within the route for authors
. Let's implement it step by step as follows:
Note: A boilerplate application is provided below the following steps. Click the "Run" button to launch the application.
Use Active Record associations to create a relationship between Book
and Author
models. A book belongs to a particular author, and each author can have multiple books. The following commands are used to generate the models:
rails generate scaffold Author username:stringrails generate scaffold Book content:text author:references
The first command generates a Rails scaffold for an Author
model with a username
attribute of string data type.
The second command generates a scaffold for a Book
model, with a content
attribute of text data type, and an author
attribute that references the Author
model.
It creates a migration file, <random_number>_create_books.rb
, in the ./db/migrate/
directory containing the following code:
class CreateBooks < ActiveRecord::Migration[5.2]def changecreate_table :books do |t|t.text :contentt.references :author, foreign_key: truet.timestampsendendend
Note: The table includes a column for an author foreign key. This key will take the form of
author_id
.
It also creates the following Book
model file book.rb
in the ./app/models/
directory:
class Book < ApplicationRecordbelongs_to :authorend
It specifies that the Book
object belongs to the Author
object using the belongs_to
method, which creates an association between the two models. This means that the Book
object will have the author_id
attribute that references the primary key of the Author
object, and that Book
objects can be accessed through an associated Author
object.
For the parent model i.e. Author
, we have to add the association manually. Go to the ./app/models/author.rb
file, and add the following code to it:
has_many :books
The has_many
method is used to establish a one-to-many association between the Author
model and the Book
model. This means that an instance of the Author
model can have many associated Book
instances.
The Author
model will look like the following:
class Author < ApplicationRecordhas_many :booksend
The models are ready now. Next, migrate the database and dummy data in it. Execute the following command in the terminal to run the migrations:
rails db:migrate
Add some dummy data in the database. We are using the following seed data to insert data in the database in the ./db/seeds.rb
file:
taylor = Author.create!(username: "Taylor")Book.create!([{content: "Red (Taylor's Version)",author: taylor},{content: "All Too Well (Taylor's Version)",author: taylor},{content: "We Are Never Ever Getting Back Together (Taylor's Version)",author: taylor},{content: "Begin Again (Taylor's Version)",author: taylor}])
Run the following command in the terminal to add the seed data:
rails db:seed
The command above will create an author and add multiple books that belong to that author.
Next, set up the routes in the ./config/routes.rb
file. Currently, it has the following:
Rails.application.routes.draw doresources :booksresources :authors# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html# Defines the root path route ("/")# root "articles#index"end
The code above shows that the routes for the resources are not dependent at all. Change the code to the following to include nested routing:
Rails.application.routes.draw do# Nested routesresources :authors doresources :booksend# show booksresources :books# Adding root pathroot 'authors#index'end
The first section of the code establishes a nested route between the Author
and Book
resources. This means that a book resource is nested under an author resource, and its URL path includes the ID of the associated author.
The second section of the code creates standard routes for the Book
resource, outside of the nested route. This means that a book can also be accessed independently of its association with an author.
The third section of the code adds a root path to the application, which means that the default URL for the application will be the index
action of the AuthorsController
.
In the last step, update the BooksController
to show the books that belong to some specific author. We just need to update the index
and show
method in the ./app/controllers/books_controller.rb
file with the following code:
# Index controllerdef indexif params[ :author_id]@books = Author.find_by_id(params[:author_id]).bookselse@books = Book.allendend# Show controllerdef show@book = Book.find(params[:id])end
The first action is the index
action. It checks if the :author_id
parameter is present in the request URL parameters. If it is, it finds the author with the ID specified in the :author_id
parameter and assigns the books associated with that author to an instance variable @books
. If :author_id
is not present, it simply assigns all books in the database to @books
. This action is typically used to display a list of books, and if the :author_id
parameter is present, it displays the books by that author.
The second action is the show
action. It finds the book with the ID specified in the :id
parameter and assigns it to an instance variable @book
. This action is typically used to display the details of a single book.
Look at the following code, it has implemented all of the steps mentioned above:
//= link_tree ../images //= link_directory ../stylesheets .css //= link_tree ../../javascript .js //= link_tree ../../../vendor/javascript .js
Note: Click on the "Run" button to execute the application. Also, click on the URL provided after "Your app can be found at:" to open the application in a new tab.
The application displays the authors on the root page. Once we click the "Show this author," it displays the information of that specific author. Now, we can append /books
in the URL, it will display all of the books belonging to that author.
In this way, we can create a nested route for the books that is associated with an author. We can also append /2
at the end of the URL. The resulting URL structure might look something like this: /authors/1/books/2
, where 1
is the ID of the author and 2
is the ID of the book.
By using nested routing, we can easily access all of the books associated with a particular author, and create, update and delete books in the context of that author. We can also generate URL helpers like author_book_path
and new_author_book_path
to easily create links to these nested routes. Overall, nested routing allows for a more intuitive and organized URL structure in our Rails application.
Free Resources