Rails Slug Routing using Param and Path

Order matters!
What I wanted was a rails 7 app that can navigate to categories from the root path '/' using the slug of category.  But I still want to be able to go to a scaffold's index with /icons or /instruments.  A module ReservedSlugs will protect creating any categories with slugs that are being reserved by these icons, flickr_photos or whatever else.

But you'll see because of my route config, going to /instruments will give me an error.  It's supposed to go to instruments index, but it's looking for a category named instruments instead!
      
          
#models/concerns/reserved_slugs.rb
module ReservedSlugs
  RESERVED_SLUGS = %w(flickr_photos categories instruments makes up icons)
end

# models/category.rb
class Category < ApplicationRecord
  include ReservedSlugs
  validates :slug, exclusion: { in: RESERVED_SLUGS }
  validates(:slug, :title, presence: true)
  validates_uniqueness_of :slug

  def to_param
    slug
  end
end
      
    
      
          
# config/routes.rb
Rails.application.routes.draw do
  resources :makes
  get 'dashboard/index'
  get 'dashboard' => 'dashboard#index'
  resources :flickr_photos

  get 'categories' => 'categories#index', as: 'category_index'
  resources :categories, except: [:index], param: :slug, path: '/', constraints: :slug.in?(ReservedSlugs::RESERVED_SLUGS) do
    resources :makes
  end

  resources :icons
  get 'instruments' => 'categories#index', as: 'category_index'
  resources :instruments do
    resources :flickr_photos
  end

  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
  # Can be used by load balancers and uptime monitors to verify that the app is live.
  get "up" => "rails/health#show", as: :rails_health_check
  # Defines the root path route ("/")
  root "instruments#index"
end
      
    
In routes the categories resource is sandwiched between :flickr_photos and before :instruments.
going to /instruments was giving me this error

Solution

The fix is to add the categories route definition at the end, so order matters.

You'll see the constraints: :slug.in? was my idea to fix this but it is not even needed.  The first routes take presedence over the last one so I could remove this and now resources :categories looks like this:
lang-ruby
      
          
# this will do the trick
Rails.application.routes.draw do
  resources :makes
  get 'dashboard/index'
  get 'dashboard' => 'dashboard#index'
  resources :flickr_photos
  resources :icons
  resources :instruments do
    resources :flickr_photos
  end
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
  # Can be used by load balancers and uptime monitors to verify that the app is live.
  get "up" => "rails/health#show", as: :rails_health_check
  # Defines the root path route ("/")
  root "instruments#index"

  get 'categories' => 'categories#index', as: 'category_index'
  resources :categories, except: [:index], param: :slug, path: '/' do
    resources :makes
  end
end
      
    
updated: 2024-05-18 20:06:58 UTC
back to Web development more tutorials