class Audited::Audit
* created_at
: Time that the change was performed
* request_uuid
: a uuid based that allows audits from the same controller request
* version
: the version of the model
* comment
: a comment set with the audit
* audited_changes
: a serialized hash of all the changes
* action
: one of create, update, or delete
* user
: the user that performed the change; a string or an ActiveRecord model
* auditable
: the ActiveRecord model that was changed
Audit saves the changes to ActiveRecord models. It has the following attributes:
def self.as_user(user, &block)
by +user+. This method is hopefully threadsafe, making it ideal
All audits made during the block called will be recorded as made
def self.as_user(user, &block) Thread.current[:audited_user] = user yield ensure Thread.current[:audited_user] = nil end
def self.assign_revision_attributes(record, attributes)
- Private: -
def self.assign_revision_attributes(record, attributes) attributes.each do |attr, val| record = record.dup if record.frozen? if record.respond_to?("#{attr}=") record.attributes.key?(attr.to_s) ? record[attr] = val : record.send("#{attr}=", val) end end record end
def self.audited_classes
def self.audited_classes audited_class_names.map(&:constantize) end
def self.reconstruct_attributes(audits)
- Private: -
def self.reconstruct_attributes(audits) attributes = {} result = audits.collect do |audit| attributes.merge!(audit.new_attributes)[:version] = audit.version yield attributes if block_given? end block_given? ? result : attributes end
def ancestors
def ancestors self.class.ascending.auditable_finder(auditable_id, auditable_type).to_version(version) end
def new_attributes
def new_attributes (audited_changes || {}).inject({}.with_indifferent_access) do |attrs, (attr, values)| attrs[attr] = values.is_a?(Array) ? values.last : values attrs end end
def old_attributes
def old_attributes (audited_changes || {}).inject({}.with_indifferent_access) do |attrs, (attr, values)| attrs[attr] = Array(values).first attrs end end
def revision
Return an instance of what the object looked like at this revision. If
def revision clazz = auditable_type.constantize (clazz.find_by_id(auditable_id) || clazz.new).tap do |m| self.class.assign_revision_attributes(m, self.class.reconstruct_attributes(ancestors).merge(version: version)) end end
def set_audit_user
def set_audit_user self.user = Thread.current[:audited_user] if Thread.current[:audited_user] nil # prevent stopping callback chains end
def set_request_uuid
def set_request_uuid self.request_uuid ||= SecureRandom.uuid end
def set_version_number
def set_version_number max = self.class.auditable_finder(auditable_id, auditable_type).descending.first.try(:version) || 0 self.version = max + 1 end
def user_as_string
- Private: -
def user_as_string user_as_model || username end
def user_as_string=(user)
- Private: -
def user_as_string=(user) # reset both either way self.user_as_model = self.username = nil user.is_a?(::ActiveRecord::Base) ? self.user_as_model = user : self.username = user end