Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 652
Ron Garrity Avatar asked Jan 16 '23 11:01

Ron Garrity


1 Answers

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

like image 55
Frederick Cheung Avatar answered Jan 29 '23 08:01

Frederick Cheung