Rescue_From Actioncontroller::Routingerror in Rails 4

rescue_from ActionController::RoutingError doesn't work

The ActionController::RoutingError is raised when Rails tries to match the request with a route. This happens before Rails even initializes a controller - thus your ApplicationController never has a chance to rescue the exception.

Instead the Rails default exceptions_app kicks in - note that this is an app in the Rack sense - it takes a ENV hash with a request and returns a response - in this case the static /public/404.html file.

What you can do is have your Rails app handle rendering the error pages dynamically instead:

# config/application.rb
config.exceptions_app = self.routes # a Rack Application

# config/routes.rb
match "/404", :to => "errors#not_found", :via => :all
match "/500", :to => "errors#internal_server_error", :via => :all

You would then setup a specific controller to handle the error pages - don't do this in your ApplicationController class as you would be adding a not_found and internal_server_error method to all your controllers!

class ErrorsController < ActionController::Base
protect_from_forgery with: :null_session

def not_found
render(status: 404)

def internal_server_error
render(status: 500)

Code borrowed from Matt Brictson: Dynamic Rails Error Pages - read it for the full rundown.

How to use RoutingError ActionController::RoutingError


redirect_to root_path, notice: 'Unknown Route' if !model


if !model
params[:controller] = 'index'

Rails 4 Grape API ActionController::RoutingError

By specifying cascade false you're saying Grape should be allowed to handle HTTP errors without interference from Rails. Consequently, when an unmatched URI beneath your API's mount point is requested, no ActionController::RoutingError is generated (this would have been done by Rails) and instead the output from Grape's default "unmatched route" handler is returned verbatim. Somewhat unhelpfully, this handler generates a plain "Not Found" message even when format :json has been specified, and that is the behaviour you're seeing.

The solution is to provide your own matchers to catch routes other than those specified in your V1 and V2 modules. Try adding this code to API::Base beneath the three mount statements:

# Generate a properly formatted 404 error for all unmatched routes except '/'
route :any, '*path' do
error!({ error: 'Not Found',
detail: "No such route '#{request.path}'",
status: '404' },

# Generate a properly formatted 404 error for '/'
route :any do
error!({ error: 'Not Found',
detail: "No such route '#{request.path}'",
status: '404' },

Naturally you'll want to edit the body of each route block to suit your needs.

For some reason both blocks seem to be necessary to catch all unmatched routes; this is a limitation of either Grape's matcher syntax or my understanding.

Related Topics

Leave a reply