I am a massive fan of ActiveSupport callbacks and use them frequently. This allows me to chain behaviours together; essentially using data storage as an event based system to enforce business logic. An example of this, is to use after_create_commit callbacks to automatically trigger an email that needs to be sent; such as welcome user email, to automatically generate some accounting record, or an admin email notification.
This does have some drawbacks however. It means that you really need to have a good grasp of the domain logic; and means that it becomes critically important to choose the correct way to update the record (update_column vs update_attribute) lest you fail to trigger important business logic, or trigger them when you shouldn’t. But generally, when used appropriately I find them invaluable. But sometimes you might find yourself in a situation where you need to run some code (such as in a rake task) where you cannot influence the method used to update the database, but the callbacks must not be executed.
As I said, if you have direct control over the ActiveRecord relation, then its easy:
@object.update_column(:the_attribute, 'value') @object.update_columns(attributes)
These will update the database, but skip validations and callbacks.
But if the updates are being triggered by another class/code outside of the scope or control of where you are, this wont work. Perhaps you care calling a method of a related class, and that method specifies .update_attribute
and you cannot change it. What then?
Fortunately, there is a solution.
Lets say you have a class definition:
class User < ActiveRecord::Base
after_save :my_method
end
There are 2 ways you can save the object without triggering the callback.
Method #1:
User.send(:create_without_callbacks) User.send(:update_without_callbacks)
But thats super gross! Using .send is a code smell if ever there was one.
Method #2:
User.skip_callback(:save, :after, :my_method)
User.create!
This is much more civilised. What’s more, after you’ve run your rspec, mock, rake task whatever: you can reset the callback with: User.set_callback(:save, :after, :my_method)
.