1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
# frozen_string_literal: true
# == ReportableChanges concern
#
# Keeps changes between the values of attributes when the object is loaded
# from persistence and all subsequent saves. This can be useful where there
# are multiple save operations on an object in a given request context and
# final hooks might need access to the cumulative delta, not just that of the
# most recent save.
#
# Used by Issuable.
#
module ReportableChanges
extend ActiveSupport::Concern
def as_json(options = {})
options[:except] = [*options[:except], "reportable_changes"]
super(options)
end
# Maintains a hash of cumulative changes to attributes between when the object
# was loaded from persistence and its most recent save.
#
# This is called by ActiveRecord (and other implementations of
# ActiveModel::Dirty) once attribute changes are persisted.
def changes_applied
super.tap do
previous_changes.each do |attr, (previous, current)|
if reportable_changes_store.include?(attr)
reportable_changes_store[attr][1] = current
else
reportable_changes_store[attr] = [previous, current]
end
end
end
end
# Returns a hash of attributes that were changed between when the object was
# initially loaded from persistence (or newly created) and its most recent
# save. This is in constrast to ActiveModel::Dirty#previous_changes which
# resets the change state after every save.
#
# person = Person.find_by_name("bob")
# person.name # => "bob"
#
# person.name = "robert"
# person.save
# person.previous_changes # => {"name" => ["bob", "robert"]}
# person.reportable_changes # => {"name" => ["bob", "robert"]}
#
# person.title = "mr"
# person.save
# person.previous_changes # => {"title" => [nil, "mr"]}
# person.reportable_changes # => {"name" => ["bob", "robert"], "title" => [nil, "mr"]}
#
# person.name = "rob"
# person.save
# person.previous_changes # => {"name" => ["robert", "rob"]}
# person.reportable_changes # => {"name" => ["bob", "rob"], "title" => [nil, "mr"]}
def reportable_changes
reportable_changes_store.clone
end
# Reset the reportable changes only when the record is reloaded from persistence.
# See ActiveRecord::AttributeMethods::Dirty#reload
def reload(*)
super.tap do
reportable_changes_store.clear
end
end
# Reset the reportable changes when explicitly requested.
# See ActiveModel::Dirty#clear_changes_information
def clear_changes_information(*)
super.tap do
reportable_changes_store.clear
end
end
private
def reportable_changes_store
@reportable_changes_store ||= HashWithIndifferentAccess.new
end
end
|