Fork me on GitHub
Subscribe to RSS Feed

Elijah Miller

11 Feb 2009

Passing Data With Ruby Exceptions

Have you ever needed more than the exception class, error message and back-trace when handling an exception?

I’ve run into this situation a few times, most recently while adding some automatic cache expiry to stale_object_destroyer when it rescues a ActiveRecord::StaleObjectError.

First we subclass an exception and add an accessor for the data we’d like to pass and add it to the initialize method for easy construction.

class MyException < StandardError
  attr_accessor :object

  def initialize(message = nil, object = nil)
    super(message)
    self.object = object
  end
end

The only other important bit is how you raise this new exception.

raise MyException.new("Too Lazy", object)

A realistic example

class CacheError < StandardError
  attr_accessor :object

  def initialize(message = nil, object = nil)
    super(message)
    self.object = object
  end
end

class User < ActiveRecord::Base
  attr_accessor :name

  def save_with_cache_update
    raise CacheError.new("Object is Stale", self) if stale?
    save
  end

  def stale?
    # ...
  end
end

begin
  user = User.find_by_name("Billy Mays")
  # ...
  user.save_with_cache_update
rescue CacheError => err
  puts "Rescued #{err.inspect} on user named #{err.object.name.inspect}"
  err.object.expire_cache
  retry
end