| name | vanilla-rails-routing |
| description | Use when defining Rails routes, organizing controller directories, or adding resources - enforces resource extraction, shallow nesting, resolve helpers, and module scoping |
Vanilla Rails Routing
Routes mirror controller directory structure. Every route points to a controller in the matching namespace.
Resource Extraction (State as Resources)
State changes become singular nested resources, not custom actions:
resources :cards do
post :close
post :archive
end
resources :cards do
resource :closure, only: [:create, :destroy]
resource :archival, only: [:create, :destroy]
end
resource (singular) = one state per parent. create = enter state. destroy = leave state.
Controller Directory Mapping
Route nesting mirrors app/controllers/ directory:
resources :boards do
resources :cards do
resource :closure
end
end
Rule: If a route is nested under boards, the controller lives in boards/ directory.
Shallow Nesting
Avoid deeply nested URLs. Use shallow: or flatten when resource has its own identity:
/boards/1/cards/2/comments/3/reactions/4
resources :boards do
resources :cards, shallow: true
end
Rule: If you can look up the resource by its own ID, it doesn't need parent in URL.
Module Scoping
Group related controllers under modules for admin/API/etc:
namespace :admin do
resources :accounts
end
scope module: :api do
resources :cards
end
scope "/api" do
resources :cards
end
| Method | URL prefix | Module prefix | Use when |
|---|
namespace | Yes | Yes | Admin panel, API versioning |
scope module: | No | Yes | Alternate controller, same URL |
scope path: | Yes | No | URL prefix, same controller |
Resolve Helpers
Use resolve to control polymorphic URL generation:
resolve("Card") { |card| [card.board, card] }
Use when polymorphic routing needs explicit parent context.
Direct Routes
Name custom routes for URL helpers:
direct(:homepage) { "/" }
direct(:dashboard) { |account| "/#{account.to_param}/dashboard" }
Quick Reference
| Pattern | Use | Avoid |
|---|
resource :closure | Singular state resource | post :close |
resources :cards, shallow: true | 2+ nesting levels | Deep nesting >3 levels |
namespace :admin | Admin/API sections | Manual path + module |
resolve("Card") | Polymorphic URL control | String interpolation in paths |
Controller at boards/cards_controller.rb | Nested route under boards | Controller location mismatch |
Red Flags
- Custom member/collection actions for state changes → extract resource
- Controller file not matching route nesting → move controller
- 3+ levels of URL nesting → use
shallow: or flatten
url_for generating wrong paths → add resolve
- Route with no corresponding controller directory → create directory