4

I have two models that when saving certain types of data, it causes the database to throw an exception. I can convert the data before saving to avoid the exception, but the conversion is expensive and the exception happens very rarely.

So, I was wondering if it's possible to create an override of the model.save method, and catch an exception that's thrown from the database? Would that work?

For example:

def save
  begin
    super
  rescue Exception => e
    if e.is_a? ActiveRecord::StatementInvalid
      # Do some processing and resave
    end
  end
end

The reason why I'd like to do this is because I've already had to repeat a big chunk of handling code between the two models that have this problem, and also because I'd like to avoid the potential issue of calling save elsewhere later, but not adding in the exception handling code.

For instance, when writing some test code and calling save directly, the error data threw an exception.

So, a few questions:

  1. Is it even possible to catch an exception from within a save or save! method?
  2. After fixing the data, how do I attempt to save again? Do I just call super() again?
  3. Is there a better way of handling this?

Thank you very much.

michaeldwp
  • 431
  • 5
  • 10

1 Answers1

3

I wouldn't override the default behaviour of save, I would simple create my own method.

def save_with_exception_handler
  begin
    self.save!
  rescue Exception => e
    if e.is_a? ActiveRecord::StatementInvalid
      # Do some processing and resave
    end
  end
end

Give it a better name that makes sense in your context, obviously. Then simply call where you are currently calling save:

model_instance.save_with_exception_handler
Toby Hede
  • 36,755
  • 28
  • 133
  • 162
  • 2
    Thanks for the idea, that would definitely work. The thing is, doing it this way I have to rely on my remembering to call that method over save or save!. In my testing, by default I went with save(), which caused the exception to be thrown and me to revisit this issue, so I'd prefer to override save, if it's possible. Interestingly, I tried overriding save() and forcing the exception to be thrown in a test, and there was no exceptions caught. Any idea why that might be, considering that I'm using the same test with the data that typically would cause an exception to be thrown? Thanks again. – michaeldwp Jul 24 '10 at 22:06
  • I had a similar issue with destroy... if you make any progress on catching (rescuing) exceptions raised by the base class from an overriding function, please post it in here :) – Cosmin Atanasiu Jun 20 '13 at 04:46
  • Be careful with the extra "Exception" on rescue line. Always be careful when manipulating it, you have to be sure on what's following. Like explained here : http://stackoverflow.com/questions/10048173/why-is-it-bad-style-to-rescue-exception-e-in-ruby – lboix Jun 05 '14 at 02:57