How to save a model without running callbacks in Rails

at. picture at. · Jan 27, 2014 · Viewed 43.6k times · Source

I need to calculate values when saving a model in Rails. So I call calculate_averages as a callback for a Survey class:

before_save :calculate_averages

However, occasionally (and initially I have 10k records that need this operation) I need to manually update all the averages for every record. No problem, I have code like the following:

Survey.all.each do |survey|
  survey.some_average = (survey.some_value + survey.some_other_value) / 2.to_f
  #and some more averages...
  survey.save!
end

Before even running this code, I'm worried the calculate_averages is going to get called and duplicate this and probably even cause some problems with the way I'm doing things. Ok, so then I think, well I'll just do nothing and let calculate_averages get called and do its thing. Problem there is, first, is there a way to force callbacks to get called even if you made no changes to the record?

Secondly, the way averages are calculated it's far more efficient to simply not let the callbacks get called at all and do the averages for everything all at once. Is this possible to not let callbacks get called?

Answer

vee picture vee · Jan 27, 2014

I believe what you are asking for can be achieved with ActiveSupport::Callbacks. Have a look at set_callback and skip_callback.

In order to "force callbacks to get called even if you made no changes to the record", you need to register the callback to some event e.g. save, validate etc..

set_callback :save, :before, :my_before_save_callback

To skip the before_save callback, you would do:

Survey.skip_callback(:save, :before, :calculate_average). 

Please reference the linked ActiveSupport::Callbacks on other supported options such as conditions and blocks to set_callback and skip_callback.