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