Ruby On Rails : Exception Handling Best practices

There are various ways to rescue from exceptions raised in Rails App.

The most basic is

begin
.........
rescue NameOfException => exc
   logger.error("Message for the log file #{exc.message}")
   flash[:notice] = "Store error message"
   redirect_to(:action => 'index')
end

Or you can render a static HTML file namely public/401.html or public/400.html.erb

rescue NameOfException => exc
   logger.error("Message for the log file #{exc.message}")
   flash[:notice] = "Store error message"
   render file: "#{Rails.root.to_s}/public/401.html", status: :unauthorized
end

 Global Exception Handling in Rails

To handle globally (in application_controller.rb) or scoped to specific controller you can use the following syntax:

rescue_from CanCan::AccessDenied do
 render file: "#{Rails.root.to_s}/public/401.html", status: :unauthorized
end
rescue_from ActiveRecord::RecordNotFound do |exception|
 # It show the error in development mode
 throw exception if Rails.env === 'development'
 render file: "#{Rails.root.to_s}/public/400.html", status: :bad_request
end

or

if params[:url_code] && @pact.nil?
  raise Pundit::NotAuthorizedError,
        "You are not authorized to perform this action."
else

you can pass the error message like in the above example

syntax is

raise ExceptionClass, "Context specific error message"

and you can access this message in the exception handling method param.

rescue_from ExceptionClass, with: :oops_something_happened

def oops_something_happened(error = OpenStruct.new({message: nil}))
  flash[:error] = error.message || "You are not authorized to perform this action."
  redirect_to(request.referrer || root_path)
end

More Better Way:

To change this behavior of Rails to handle specific type of exception we need to modify the application’s config file. /config/application.rb

config.action_dispatch.rescue_responses["ProductsController::Forbidden"] = :forbidden
config.action_dispatch.rescue_responses["ActiveRecord::RecordNotFound"] = :forbidden

Here we set config.action_dispatch.rescue_responses which is a hash where the key represents the name of the exception that we want to handle and the value is the status code, in this case :forbidden (we can use the status codes that Rack uses instead of a numeric HTTP status). To learn more about how Rack handles status codes take a look at the documentation for Rack::Utils where we’ll find the names for each status code and how it’s converted to a symbol. If we visit the a product’s page now after restarting our app we’ll see a 403.html error page.

Next we’ll show you some of the exceptions that Rails maps by default. For example if we trigger a route that doesn’t exist we’ll see a 404 error instead of a 500. Most of these are defined in the Rails source code in the ExceptionWrapper class. This class sets the default rescue_responses hash that we configured earlier and one of the values set is ActionController::RoutingError which is set to :not_found. This is what we see in the application with the 404 status.

Note:

For this feature you must have files like 400.html, 404.html, etc inside the public dir.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s