Search code examples
ruby-on-railsroutesruby-on-rails-5

Route constraints: raising exception when there's no match


Given a Rails route constraint like this:

class UserConstraint
  def matches?(request)
    User.where(code: request.path_parameters[:code]).any?
  end
end

This won't work because of a subroute.

routes.rb:

constraints UserConstraint.new do
  get ':code', to: 'documents#index', as: :documents
  get ':code/*slug', to: 'documents#show', as: :document
end

It just returns the following:

ActiveRecord::RecordNotFound:
Couldn't find User with 'slug'={:code=>"show"}

Is this only solvable with more constraints?


Solution

  • For anyone looking for an answer for something similar this is how I solved it.

    If you have globbed routes like I did it's way easier to write separate constraints for them.

    routes.rb

    constraints UserConstraint.new do
      get ':code', to: 'documents#index', as: :documents
    end
    
    constraints SlugConstraint.new do
      get ':code/*slug', to: 'documents#show', as: :document
    end
    

    user_constraint.rb

    class UserConstraint
      def matches?(request)
        result = User.where(code: request.path_parameters[:code]).any?
        raise Errors::NoCode, 'User not found' unless result
    
        result
      end
    end
    

    slug_constraint.rb

    class SlugConstraint
      def matches?(request)
        slug = "#{request.path_parameters[:code]}/#{request.path_parameters[:slug]}"
        result = Document.where(slug: slug).any?
        raise Errors::NoDocumentSlug, 'Document not found' unless result
    
        result
      end
    end