Module: StandardAudit::ReferencePreloading
- Extended by:
- ActiveSupport::Concern
- Included in:
- AuditLog
- Defined in:
- lib/standard_audit/reference_preloading.rb
Overview
Batch resolution of the GlobalID-backed actor / target / scope
references on a page of audit rows, plus the per-row memo the readers
consult.
Why this exists: AuditLog#actor resolves actor_gid through
GlobalID::Locator.locate, which is one query per row. Rendering N rows
that each read actor and target issues O(N) lookups — an N+1 that
Prosopite fails in every consuming app. Before this concern existed, apps
worked around it by defining their own preloaded_actor= writer (or
reaching into @preloaded_actor with instance_variable_set) and
hand-rolling a per-type whitelist loader.
Memo semantics
The memo is a Hash consulted with key?, not a pair of ivars checked with
defined?. That distinction matters: a reference that was preloaded but
whose record has since been deleted memoizes nil, and reads back as
nil without falling through to a query. "Preloaded, and the answer is
nothing" is therefore distinct from "not preloaded".
actor= / target= / scope= populate the memo too, since the writer
already holds the record. reload clears it.
Batched writes
StandardAudit.batch { ... } flushes through insert_all! and never
instantiates an AuditLog, so nothing in this concern runs on that path —
neither the memo nor the writers. It is a no-op for batched writes by
construction, not by accident.
Constant Summary collapse
- REFERENCES =
The GlobalID-backed reference columns.
scopeis preloadable but not in the defaultrefs:set, since most read surfaces render actor/target only. %i[actor target scope].freeze
- DEFAULT_REFS =
%i[actor target].freeze
Instance Method Summary collapse
-
#preloaded_references ⇒ Object
The memo itself.
- #reference_preloaded?(ref) ⇒ Boolean
-
#reload ⇒ Object
Drops the memo so the next read re-resolves from the (possibly changed) gid columns.
-
#write_preloaded_reference(ref, record) ⇒ Object
See
preloaded_references— gem-internal, but public so the class-level preloader can reach it.
Instance Method Details
#preloaded_references ⇒ Object
The memo itself. Public because preload_references writes through it
from the class side; treat it as gem-internal — preloaded_actor= and
actor_preloaded? are the supported surface.
245 246 247 |
# File 'lib/standard_audit/reference_preloading.rb', line 245 def preloaded_references @preloaded_references ||= {} end |
#reference_preloaded?(ref) ⇒ Boolean
249 250 251 |
# File 'lib/standard_audit/reference_preloading.rb', line 249 def reference_preloaded?(ref) preloaded_references.key?(ref.to_sym) end |
#reload ⇒ Object
Drops the memo so the next read re-resolves from the (possibly changed) gid columns.
261 262 263 264 |
# File 'lib/standard_audit/reference_preloading.rb', line 261 def reload(...) @preloaded_references = nil super end |
#write_preloaded_reference(ref, record) ⇒ Object
See preloaded_references — gem-internal, but public so the class-level
preloader can reach it.
255 256 257 |
# File 'lib/standard_audit/reference_preloading.rb', line 255 def write_preloaded_reference(ref, record) preloaded_references[ref.to_sym] = record end |