Nesting a resource: putting a "belongs to" relationship into the URL
Where the earlier routes course stopped
Rails routes: basics, earlier in this series, showed resources :courses, param: :slug, only: [ :show ], this app's routing for public course pages. Every resources call in that course is a single, standalone resource; none of its seven lessons puts one resources block inside another. That course covered the seven-routes-in-one-line convention in depth and never reached the case where one resource can't exist without another.
A Catalog::Lesson is that kind of resource. Every lesson belongs to one course, and this app's admin routing says so in the URL itself.
The route, from this app's config/routes.rb
namespace :admin do
namespace :catalog do
resources :courses do
resources :lessons, shallow: true do
# ...
end
end
end
end
One resources :lessons block, written inside the do ... end of resources :courses. bin/rails routes shows what that nesting produces for a lesson's create action:
admin_catalog_course_lessons POST /admin/catalog/courses/:course_id/lessons(.:format) admin/catalog/lessons#create
:course_id is a new path segment that a standalone resources :lessons would never generate. Nesting one resource inside another does more than organize the routing file: it adds the parent's id to the URL, and Rails hands that id to the controller as params[:course_id], which Admin::Catalog::LessonsController#set_course reads:
def set_course
@course = Admin::Catalog::FindCourseQuery.call(id: params[:course_id]).course
end
Why the URL says it at all
A lesson's create action needs to know which course it's adding to before it can do anything. Two separate resources, resources :courses and resources :lessons declared side by side, could still work: the request could carry a course id some other way, in a hidden field or the session. Nesting puts that requirement into the URL's shape instead, where it's visible, bookmarkable and impossible to leave out: /admin/catalog/courses/:course_id/lessons, not /admin/catalog/lessons. The relationship between a lesson and its course, which the database records (every Catalog::Lesson has a course_id foreign key), gets a matching shape in the routes that manage it.
What this course covers
Seven lessons, each checked against this app's config/routes.rb, its controllers and Rails' installed source. Lesson 2 covers shallow: true, the option already on this app's resources :lessons line, and what it flattens and leaves nested. Lesson 3 covers the singular resource keyword, with no plural and no :id, used four times in this routing block. Lesson 4 covers member do ... end, which this app's routes use twice for a custom reorder action. Lesson 5 covers module: and scope module:, which route a URL to a controller in a subdirectory. Lesson 6 shows how shallow: true treats a plural resource nested further down differently from a singular one, both in this block. Lesson 7 traces one nested route from URL to controller, tying the lessons together.
Keep going with lesson 2
resources :lessons, shallow: true: Rails' reason for the option
Rails' docs explain shallow: true, which keeps index, new and create nested and flattens member actions to :id.
A free account also gives you the quizzes, your progress and notes, and the discussion.