Class: PaperTrailDiff::ActivityTransactionGrouper

Inherits:
Object
  • Object
show all
Defined in:
lib/paper_trail_diff/activity_transaction_grouper.rb,
sig/generated/paper_trail_diff/activity_transaction_grouper.rbs

Overview

Reports one saved transaction as one activity step.

A parent and its children saved together produce a version each, and the timeline reports the gap between every pair of them. One deliberate action therefore arrives as several steps, none of which is the thing the person did.

A version records the state before its own event. Two things follow.

The change a step reports was made by the event that opens it, so a step belongs to the transaction of its from_boundary, and consecutive steps sharing one are the parts of a single save. Grouping on the closing boundary instead would credit each change to whoever made the next one.

And a child's new value is revealed only by something later -- a further version of that child, its destroy version, or the live row. Inside a transaction there is usually none of those yet, so a step can read as empty while a change was in fact made at that boundary, and the change surfaces later, folded in with whatever that step carried. Grouping puts it back together with the save it belongs to.

Merging compares the group's outer snapshots rather than combining the diffs between them. A field set and then restored inside one transaction has not changed, and only a comparison of the endpoints can say so.

A boundary with no transaction groups with nothing. PaperTrail leaves the column nil outside a transaction, and a custom version class need not carry it at all; treating those as one shared transaction would merge unrelated history into a single step.

Instance Method Summary collapse

Constructor Details

#initialize(steps, retain:) ⇒ ActivityTransactionGrouper

: (Array, retain: bool) -> void

Parameters:



36
37
38
39
# File 'lib/paper_trail_diff/activity_transaction_grouper.rb', line 36

def initialize(steps, retain:)
  @steps = steps
  @retain = retain
end

Instance Method Details

#callArray[ActivityStep]

: () -> Array

Returns:



42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/paper_trail_diff/activity_transaction_grouper.rb', line 42

def call
  grouped = [] #: Array[Array[ActivityStep]]
  @steps.each do |step|
    open_group = grouped.last
    if open_group && continues?(open_group, step)
      open_group << step
    else
      grouped << [step]
    end
  end
  grouped.map { |group| merge(group) }
end

#continues?(open_group, step) ⇒ Boolean

: (Array, ActivityStep) -> bool

Parameters:

Returns:

  • (Boolean)


61
62
63
64
65
66
# File 'lib/paper_trail_diff/activity_transaction_grouper.rb', line 61

def continues?(open_group, step)
  transaction = step.from_boundary.transaction_id
  return false if transaction.nil?

  open_group.last.from_boundary.transaction_id == transaction
end

#merge(group) ⇒ ActivityStep

Rebuilt rather than reused even when a group holds one step, so that every returned step retains its snapshots on the same terms. : (Array) -> ActivityStep

Parameters:

Returns:



71
72
73
74
75
76
77
78
79
80
81
# File 'lib/paper_trail_diff/activity_transaction_grouper.rb', line 71

def merge(group)
  first = group.first #: ActivityStep
  last = group.last #: ActivityStep
  ActivityStep.between(
    from_boundary: first.from_boundary,
    to_boundary: last.to_boundary,
    from_snapshot: first.from_snapshot,
    to_snapshot: last.to_snapshot,
    retain: @retain
  )
end