Preparing for Rails 2.0: Controller-based exception handling

Tweet

Since Ruby is a pure Object-Oriented Language, exceptions play a big role in the flow of control. Previously, you had the choice of rescuing exceptions at a local level or you could override the rescue_action method in your controller.

The former method gave you really fine-grained control of what to do in the case of an exception:


begin
    user.save!
rescue ActiveRecord::RecordInvalid
    render :action => 'new'
end

In this case, if the ActiveRecord::RecordInvalid exception is raised (the save! method will raise this if validation fails) Rails will render the ‘new’ action. It became clear, though that adding begin/rescues around the same methods is pretty time consuming and not very DRY – which is where the rescue_action became helpful:


def rescue_action(exception)
  if exception == ActionView::TemplateError
    render :template => 'errors/404'
  else
    super
  end
end

This (rather contrived) example will trap any ActionView::TemplateError and render the 404.erb file in the /app/views/errors directory. You are able to drop that method into any controller (including app_controller), but again, there is a lot of work involved in setting them up, making sure each controller performs the correct action for a given exception, which is why Rails 2.0 introduces rescue_from.

rescue_from is an attribute of each controller, and allows you to define a method to run when a particular exception is called. So the above example would become:


rescue_from ActionView::TemplateError, :with => :render_404

def render_404(exception)
   render :template => 'errors/404'
end


or if you prefer to use a inline block:


rescue_from ActionView::TemplateError do { render :template => 'errors/404' }

In the current PR release, the rescue_from technique can only catch exceptions of an exact type, so it wouldn’t catch sub-classed exceptions – if you had a custom exception called MyTemplateError that extends ActionView::TemplateError the above code won’t work. The good news is a patch to edge rails fixes this issue, so the release version of Rails 2.0 will work as expected.

Get your free chapter of Level Up Your Web Apps with Go

Get a free chapter of Level Up Your Web Apps with Go, plus updates and exclusive offers from SitePoint.