File: reportable_changes.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (85 lines) | stat: -rw-r--r-- 2,739 bytes parent folder | download
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