No release in over a year
Aggregate all changes made to an ActiveRecord model inside a transaction into a single set of changes.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

AfterCommitChanges

Continuous Integration Regression Test Ruby Style Guide Gem Version

This gem addresses an issue in ActiveRecord with the saved_changes value when a record is updated multiple times in a single database transaction.

After a record is saved, you can check the set of changes with the saved_changes method using the ActiveModel::Dirty API. However, when a record is saved multiple times, the list of saved changes is reset with each save operation. This can be an issue inside of an after_commit or before_commit callback since those callbacks are only called once for the transaction and will only get the last set of changes.

This can be a problem if you have a callback that checks for changes to specific fields. Consider this model where we want to run an asychronous job when a user changes their email address:

class User < ApplicationRecord
  after_commit :notify_email_changes, if: :email_changed?

  def notify_email_changes
    NotifyEmailChangesJob.perform_later(id)
  end
end

This breaks down if a record is saved twice in a single transaction.

user.transaction do
  user.update!(email: params[:email])
  if user.last_visited_at < 1.day.ago
    user.update!(last_visited_at: Time.now)
  end
end

In the case where we update the last_visited_at field, the email_changed? method will return false since the email address was not changed in the last save operation and notify_email_changes method will not be called.

This gem addresses this issue by merging all saved changes together before calling the after_commit or before_commit callbacks so that saved_changes will return the complete list of changes for the transaction.

Usage

To use the gem, you simply need to mix it into your models. You can include it in all models by including it in your ApplicationRecord class:

class ApplicationRecord < ActiveRecord::Base
  include AfterCommitChanges
end

Installation

Add this line to your application's Gemfile:

gem "after_commit_changes"

Then execute:

$ bundle

Or install it yourself as:

$ gem install gem "after_commit_changes"

Contributing

Open a pull request on GitHub.

Please use the standardrb syntax and lint your code with standardrb --fix before submitting.

License

The gem is available as open source under the terms of the MIT License.