Module: VersionsHelper

Defined in:
app/helpers/versions_helper.rb

Overview

View helper: versions.

Constant Summary collapse

MAX_RENDERED_BYTES =

Serialized byte ceiling above which an audited value is summarised rather than
rendered or diffed.

Hashdiff.diff does LCS-style similarity matching — O(n²) on nested structures.
A Delivery#carrier_responses blob reaches ~2 MB, and one audit-trail page fed 21
of them through it: 635 s of Ruby and 89 s of GC for a single request, against only
33 ms of DB. Three such requests exhausted Puma's 12 threads and 502'd every site on
the host (outage 2026-07-20 05:28–05:39 UTC). The blob no longer reaches the audit
trail at all (see Delivery's skip_audit_for), but this guard is what keeps ANY
oversized value from doing it again.

8_192

Instance Method Summary collapse

Instance Method Details

#version_data_format_changes(data) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'app/helpers/versions_helper.rb', line 41

def version_data_format_changes(data)
  return unless (changes = data&.last)

  original = data&.first

  if original.respond_to?(:to_h) && changes.respond_to?(:to_h)
    return audit_value_omitted if audit_value_oversized?(original) || audit_value_oversized?(changes)

    diff = Hashdiff.diff(original, changes)
    tag.pre JSON.pretty_generate(JSON.parse(diff.to_json))
  else
    version_data_format_json(changes)
  end
end

#version_data_format_json(data) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
# File 'app/helpers/versions_helper.rb', line 22

def version_data_format_json(data)
  # Size first, type second: a non-Hash falls through untouched, so checking the
  # type first would let an oversized string or array straight onto the page.
  return audit_value_omitted if audit_value_oversized?(data)
  return data unless data.is_a?(Hash)

  begin
    tag.pre(JSON.pretty_generate(JSON.parse(data.to_json)))
  rescue JSON::ParserError
    data
  end
end

#version_data_format_original(data) ⇒ Object



35
36
37
38
39
# File 'app/helpers/versions_helper.rb', line 35

def version_data_format_original(data)
  return unless (original = data&.first)

  version_data_format_json(original)
end

#version_event_badge(event) ⇒ Object



17
18
19
20
# File 'app/helpers/versions_helper.rb', line 17

def version_event_badge(event)
  css_class_suffix = { 'create' => 'success', 'update' => 'secondary', 'destroy' => 'danger' }[event.to_s]
  tag.span(event, class: "badge bg-#{css_class_suffix}")
end