← recent

ActiveRecord Callbacks Trigger on Clean Objects

Since Rails 2.1, we have had dirty object checking, which prevents ActiveRecord from saving an object if if hasn’t changed. Any after_save callbacks on the model, though, will trigger (regardless of if a save actually hits the database).

I came across this issue the other day at work, and I’m not really sure how I feel about it. It doesn’t necessarily seem right or wrong, but was definitely unintuitive for me…

Since Rails 2.1, we have had dirty object checking, which prevents ActiveRecord from saving an object if if hasn’t changed:
>> person = Person.first

  Person Load (0.9ms)  

SELECT * FROM “people” LIMIT 1
=> #

>> person.save
=> true

>> person.nickname = “nick”
=> “nick”

>> person.save

  Person Update (20.6ms)  

UPDATE “people” SET “updated_at” = ‘2009-08-20 02:31:17’, “nickname” = ’nick’ WHERE “id” = 1
=> true

That part is good, but what happens when you have a callback defined?
>> Person.after_save { puts ‘After save…’ }
=> [#, @kind=:after_save, @options={}>]

>> person.nickname = nil
=> nil

>> person.save

  Person Update (2.4ms)  

UPDATE “people” SET “updated_at” = ‘2009-08-20 02:33:21’, “nickname” = NULL WHERE “id” = 1
After save…
=> true

>> person.save
After save…
=> true

As we see there, the callback gets triggered even if the save is short-circuited.

In my trivial example, the behavior isn’t terribly important either way. However, if your callback is doing something relatively expensive it may be pointless (and wasteful) to do that on a clean object. There are certainly situations where you would want it to always trigger, so I guess it’s just one of those things that a developer ought to keep in the back of his mind when coding.