iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

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…