Class: RailsAuditLog::AuditLogEntry
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- RailsAuditLog::AuditLogEntry
- Defined in:
- app/models/rails_audit_log/audit_log_entry.rb
Overview
Represents a single audited event (create, update, or destroy) for one ActiveRecord record.
Columns
- event
-
One of
"create","update","destroy". - item_type
-
Class name of the audited record (e.g.
"Article"). - item_id
-
Primary key of the audited record.
- object_changes
-
JSON hash of attribute changes in
[from, to]form. All three event types use the same format:createstores[nil, new]for every column,updatestores[old, new]for changed columns only,destroystores[final, nil]for every column. - object
-
JSON snapshot of the record’s full attributes before the change (stored when #store_snapshot is
true). - whodunnit_snapshot
-
Display name of the actor at the time of the change.
- actor_type / actor_id
-
Polymorphic reference to the actor record.
- reason
-
Optional free-text reason string.
- metadata
-
Arbitrary JSON hash (request IP, custom lambdas, etc.).
Constant Summary collapse
- EVENTS =
%w[create update destroy].freeze
- BLOB_COLUMNS =
%w[object_changes object metadata].freeze
- PERIODS =
{ "1h" => 1.hour, "24h" => 24.hours, "7d" => 7.days }.freeze
Event scopes collapse
-
#created_events ⇒ ActiveRecord::Relation
Entries for
createevents. -
#destroyed_events ⇒ ActiveRecord::Relation
Entries for
destroyevents. -
#updated_events ⇒ ActiveRecord::Relation
Entries for
updateevents.
Actor / resource scopes collapse
-
#by_actor ⇒ ActiveRecord::Relation
Entries written by a specific actor.
-
#for_resource ⇒ ActiveRecord::Relation
Entries for a specific resource class or instance.
Time scopes collapse
-
#for_period ⇒ ActiveRecord::Relation
Entries within a named period.
-
#since ⇒ ActiveRecord::Relation
Entries created at or after
time. -
#until ⇒ ActiveRecord::Relation
Entries created at or before
time.
Class Method Summary collapse
- .configure_connection! ⇒ Object private
Instance Method Summary collapse
-
#changed_attributes ⇒ Array<String>
Returns the list of attribute (and association) names that changed in this entry, derived from the keys of
object_changes. -
#diff ⇒ Hash{String => Hash}
Returns
object_changesin a named-key format convenient for display. -
#next ⇒ AuditLogEntry?
Returns the entry immediately after this one in the version chain for the same record (higher
id), ornilif this is the last entry. -
#previous ⇒ AuditLogEntry?
Returns the entry immediately before this one in the version chain for the same record (lower
id), ornilif this is the first entry. -
#reify ⇒ ActiveRecord::Base?
Reconstructs and returns the record’s state before this entry’s change.
-
#slim ⇒ ActiveRecord::Relation
Omits the three JSON blob columns (
object_changes,object,metadata) from theSELECT. -
#touching ⇒ ActiveRecord::Relation
Entries where
object_changescontains a key matchingattribute.
Class Method Details
.configure_connection! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
29 30 31 32 33 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 29 def self.configure_connection! return unless (opts = RailsAuditLog.connects_to) connects_to(**opts) end |
Instance Method Details
#by_actor ⇒ ActiveRecord::Relation
Entries written by a specific actor.
74 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 74 scope :by_actor, ->(actor) { where(actor_type: actor.class.name, actor_id: actor.id) } |
#changed_attributes ⇒ Array<String>
Returns the list of attribute (and association) names that changed in this entry, derived from the keys of object_changes.
199 200 201 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 199 def changed_attributes object_changes&.keys || [] end |
#created_events ⇒ ActiveRecord::Relation
Entries for create events.
47 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 47 scope :created_events, -> { where(event: "create") } |
#destroyed_events ⇒ ActiveRecord::Relation
Entries for destroy events.
55 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 55 scope :destroyed_events, -> { where(event: "destroy") } |
#diff ⇒ Hash{String => Hash}
Returns object_changes in a named-key format convenient for display.
210 211 212 213 214 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 210 def diff return {} unless object_changes object_changes.transform_values { |from_to| { from: from_to[0], to: from_to[1] } } end |
#for_period ⇒ ActiveRecord::Relation
Entries within a named period. Valid keys: "1h", "24h", "7d".
113 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 113 scope :for_period, ->(period) { where(created_at: PERIODS[period].ago..) } |
#for_resource ⇒ ActiveRecord::Relation
Entries for a specific resource class or instance. Pass a class to get all entries for that type; pass an instance for one record.
85 86 87 88 89 90 91 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 85 scope :for_resource, lambda { |resource| if resource.is_a?(Class) where(item_type: resource.name) else where(item_type: resource.class.name, item_id: resource.id) end } |
#next ⇒ AuditLogEntry?
Returns the entry immediately after this one in the version chain for the same record (higher id), or nil if this is the last entry.
191 192 193 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 191 def next self.class.where(item_type: item_type, item_id: item_id).where("id > ?", id).order(id: :asc).first end |
#previous ⇒ AuditLogEntry?
Returns the entry immediately before this one in the version chain for the same record (lower id), or nil if this is the first entry.
183 184 185 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 183 def previous self.class.where(item_type: item_type, item_id: item_id).where("id < ?", id).order(id: :desc).first end |
#reify ⇒ ActiveRecord::Base?
Reconstructs and returns the record’s state before this entry’s change. Uses the object snapshot when available; falls back to deriving prior state from object_changes (or the live record for update entries).
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 148 def reify return nil if event == "create" klass = item_type.constantize if object.present? instance = klass.new instance.assign_attributes(object.except("id")) instance.id = object.fetch("id") { item_id } return instance end # Fallback: diff-only mode or entries recorded before snapshot support. # Filter to column names so association-change entries (e.g. tags, comments) # don't get assigned to the record as if they were scalar attributes. column_names = klass.column_names.map(&:to_s) from_attrs = (object_changes || {}) .select { |k, _| column_names.include?(k) } .transform_values { |from_to| from_to[0] } if event == "update" record = klass.find_by(id: item_id) from_attrs = record.attributes.merge(from_attrs) if record end instance = klass.new instance.assign_attributes(from_attrs.except("id")) instance.id = from_attrs.fetch("id") { item_id } instance end |
#since ⇒ ActiveRecord::Relation
Entries created at or after time.
101 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 101 scope :since, ->(time) { where(created_at: time..) } |
#slim ⇒ ActiveRecord::Relation
Omits the three JSON blob columns (object_changes, object, metadata) from the SELECT. Use on index/listing queries where blobs are not displayed to reduce I/O and avoid deserializing large payloads.
122 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 122 scope :slim, -> { select(column_names - BLOB_COLUMNS) } |
#touching ⇒ ActiveRecord::Relation
Entries where object_changes contains a key matching attribute. Uses json_extract on SQLite/MySQL and ->> on PostgreSQL.
132 133 134 135 136 137 138 139 140 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 132 scope :touching, ->(attribute) { if connection.adapter_name =~ /PostgreSQL/i # :nocov: where("object_changes->>? IS NOT NULL", attribute.to_s) # :nocov: else where("json_extract(object_changes, ?) IS NOT NULL", "$.#{attribute}") end } |
#until ⇒ ActiveRecord::Relation
Entries created at or before time.
107 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 107 scope :until, ->(time) { where(created_at: ..time) } |
#updated_events ⇒ ActiveRecord::Relation
Entries for update events.
51 |
# File 'app/models/rails_audit_log/audit_log_entry.rb', line 51 scope :updated_events, -> { where(event: "update") } |