What's New in Edge Rails: Better Exception Handling

Posted by ryan
at 8:45 AM on Monday, September 24, 2007



It’s a common pattern to redirect the user to, or render specific pages for different types of exceptions that are thrown in your application. Prior to this changeset this usually involved overloading the rescue_action_in_public method of your controllers:

1
2
3
4
5
6
7
8
9
class PostsController < ApplicationController
  def rescue_action_in_public(exception)
    case(exception)
      when ActiveRecord::RecordNotFound then render :file => '/bad_record'
      when NoMethodError then render :file => '/no_method'
      else render :file => '/error'
    end
  end
end

It’s easy to see that this can quickly grow to be an ugly mass of a case or if/else statement.

Now we’ve got a much cleaner way to map exceptions to handlers with the new rescue_from support. rescue_from maps an exception type directly to a handler method name for a very concise and direct way of dealing with exceptions:

1
2
3
4
5
6
7
8
9
10
class PostsController < ApplicationController

  # Declare exception to handler methods
  rescue_from ActiveRecord::RecordNotFound, :with => :bad_record
  rescue_from NoMethodError, :with => :show_error

  def bad_record; render :file => '/bad_record'; end
  def show_error(exception); render :text => exception.message; end

end

Note that the exception handler methods can be either no-arg methods or take the exception in question as an argument (as in show_error above).

You can also use a block or proc to specify exception handling in rescue_from:

1
2
3
4
5
6
7
class PostsController < ApplicationController

  # Declare exception to handler methods
  rescue_from(ActiveRecord::RecordNotFound) { |e| render :file => '/bad_record' }
  rescue_from NoMethodError, :with => proc { |e| render :text => e.message }

end

tags: ruby, rubyonrails

Comments

Leave a response

  1. nicolashOctober 02, 2007 @ 04:52 PM

    Can’t rescue from RoutingError: rescue_from ::ActionController::RoutingError, :with => :render_not_found # doesn’t work rescue_from ActionController::RoutingError, :with => :render_not_found # doesn’t work any ideas?

    theses work as expected: rescue_from ActiveRecord::RecordNotFound, :with => :render_not_found rescue_from ActionController::UnknownAction, :with => :render_not_found rescue_from ActiveRecord::RecordInvalid, :with => :render_record_invalid rescue_from ActiveRecord::StaleObjectError, :with => :render_stale_object_error

  2. drewOctober 09, 2007 @ 12:17 AM

    Nicolash, I don’t think the RoutingError is raised from inside the controllers so it can’t rescue them. The routing error is occurring because it couldn’t determine what controller or action to use so your controller with the rescue_from isn’t even in the picture yet.

  3. nicolashOctober 09, 2007 @ 08:47 AM

    @drew, sounds reasonable but, it works the old way… and as I understand it the new “rescue_from” should do exactly the same and just be more convinient. def rescue_action_in_public(e) case e when ::ActionController::RoutingError, ::ActionController::UnknownController render_not_found # does work as expected else super end end

  4. TrekDecember 06, 2007 @ 05:24 PM

    @nicolash, you’re quite right, it should work as before. There is a current discussion to try doing just that.

    http://dev.rubyonrails.org/ticket/10328