Ron Garrity
Ron Garrity

Reputation: 1463

after_commit not getting called after update_all

I have after_commit setup as folllows.

class MyModel < ActiveRecord::Base
  after_commit { Rails.logger.info ("commit here") }

  # ...
end

I am then wrapping update_all, which doesn't fire a callback, inside a transaction, which is supposed to fire a callback.

MyModel.transaction do
  MyModel.update_all(col: 'awesome')
end

Why isn't the after_commit being fired? I don't see "commit here" in my logs. It works for destroy just fine.

Upvotes: 6

Views: 3233

Answers (1)

Frederick Cheung
Frederick Cheung

Reputation: 84114

The way after_commit works is that whenever a record is saved it gets added to a list of records. When the transaction gets committed, rails iterates over that list calling the after commit hooks on each one.

When you do update_all the instances aren't saved individually (since they aren't actually loaded at all - rails doesn't actually know which rows were updated) and so they don't get added to the list that power after_commit.

destroy_all is different because it does actually load all the instances and delete them one by one, firing all callbacks. You'd observe similar behaviour to update_all if you used delete_all

Upvotes: 12

Related Questions