ruby-on-railsactiondispatch

Rails restrict wildcard route to certain format


I have a wildcard route in my routes.rb file:

get "*client" => "client#show"

In the controller, I look up the client in the database and display their custom page:

def show
  @client = Client.find_by(slug: params[:client])

  if @client.nil?
    render file: "client/404", layout: "error", status: :not_found
    return
  end
end

This works great, but my problem is that any asset that is not found is also being routed through my client#show handler.

This results in a pointless lookup in the database for a client and then I get a 500 error because Rails doesn't know how to render my error page for non-html formats.

My question is: How can I prevent non-HTML formats from going into my wildcard handler?

I've tried the following to no avail:

Format Constraint

Putting a scope around the route to constrain it to the HTML format:

scope :format => true, :constraints => { :format => 'html' } do
  get "*client" => "client#show"
end

This does keep assets from being routed to my handler, but unfortunately only routes pages to the handler if they explicitly end with the .html extension. Failure.

Format Default

Next, I thought I'd try a format default. Like so:

get "*client" => "client#show", :defaults => { :format => 'html' }

Unfortunately, still no workee. There is no change. My understanding is that this just sets the default format if Rails can't otherwise figure it out from the content-type header or file extension.

I'm starting to think there may not be a way to do this at the route level.


Solution

  • Since I couldn't figure out how to restrict assets from going into my handler at the route level, I just put a check at the beginning of my handler to short-circuit the handler if the request is not HTML format.

    def show
      render nothing: true, status: :not_found and return if invalid_format?
      ...
    end
    
    private
    
    def invalid_format?
      request.format != "html"
    end