Routes
Rails routes.rb defines the URL surface of the app. Resourceful routes are the default — `resources :orders` generates seven RESTful endpoints — and you add nested resources, member/collection routes, constraints, scopes, and concerns for cross-cutting URL shapes. Get this file right and most controllers fall into place.
A real-world Rails routes file
EXAMPLE
# config/routes.rb
Rails.application.routes.draw do
# 1) Root + simple static
root "home#show"
get "about", to: "pages#show", as: :about_page
# 2) Resourceful — generates 7 actions (index, new, create, show, edit, update, destroy)
resources :products
# Limit which actions
resources :orders, only: %i[index show create] do
# member route: /orders/:id/cancel
member do
post :cancel
post :ship
end
# collection route: /orders/recent
collection do
get :recent
end
# nested resource: /orders/:order_id/line_items/:id
resources :line_items, only: %i[index create destroy]
end
# 3) Singular resource — no :id (e.g. each user has ONE profile)
resource :profile, only: %i[show edit update]
# 4) Namespaced routes — for /admin paths AND Admin:: controllers
namespace :admin do
root "dashboard#show"
resources :users
resources :orders, only: %i[index show update]
end
# 5) Scoped paths — /api prefix WITHOUT Api:: controller namespace
scope :api, defaults: { format: :json } do
resources :webhooks, only: :create
end
# 6) Versioned API namespace
namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :orders
resources :products, only: %i[index show]
end
end
# 7) Constraints — accept only certain values for params
resources :stores, only: :show, constraints: { id: /\d+/ } # numeric only
get "/u/:handle", to: "users#show", constraints: { handle: /[A-Za-z0-9_-]+/ }
# 8) Subdomain constraint — admin.example.com
constraints subdomain: "admin" do
namespace :admin, path: nil do
root "dashboard#show"
end
end
# 9) Concerns — share routes across multiple resources
concern :commentable do
resources :comments, only: %i[index create destroy]
end
resources :posts, concerns: :commentable
resources :products, concerns: :commentable
# 10) Direct routes — for vanity URLs
get "sign-in", to: "sessions#new", as: :new_session
post "sign-in", to: "sessions#create"
delete "sign-out", to: "sessions#destroy", as: :destroy_session
# 11) Redirects
get "/legacy/about", to: redirect("/about", status: 301)
# 12) Catch-all fallback for SPAs (BE CAREFUL with this; place LAST)
get "*path", to: "spa#index", constraints: ->(req) {
!req.path.start_with?("/api") && !req.path.start_with?("/admin")
}
# 13) Health check (no rendering, fast)
get "healthz", to: proc { [200, {}, ["ok"]] }
end
# Run: bin/rails routes
# Filter:
# bin/rails routes -g orders # routes whose name OR path matches 'orders'
# bin/rails routes -c orders # routes for the OrdersController
# bin/rails routes --expanded # easier to read in a wide terminal
Why it matters
Resourceful routes are the right default. Reach for `member` / `collection` / `concern` / `scope` when REST does not map cleanly — then your controllers stay tiny and your URL surface is predictable. The moment routes.rb grows past about 100 lines, split it into multiple files via `draw :api` / `draw :admin` and keep each file focused.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# config/routes.rb
Rails.application.routes.draw do
resources :posts
root 'home#index'
end
Try it Yourself »
Discussion
Loading…