module Audited::Auditor::AuditedInstanceMethods

def audit_create

def audit_create
  write_audit(action: 'create', audited_changes: audited_attributes,
              comment: audit_comment)
end

def audit_destroy

def audit_destroy
  write_audit(action: 'destroy', audited_changes: audited_attributes,
              comment: audit_comment) unless new_record?
end

def audit_update

def audit_update
  unless (changes = audited_changes).empty? && audit_comment.blank?
    write_audit(action: 'update', audited_changes: changes,
                comment: audit_comment)
  end
end

def audited_attributes

List of attributes that are audited.
def audited_attributes
  attributes.except(*non_audited_columns)
end

def audited_changes

def audited_changes
  all_changes = respond_to?(:changes_to_save) ? changes_to_save : changes
  if audited_options[:only].present?
    all_changes.slice(*audited_columns)
  else
    all_changes.except(*non_audited_columns)
  end
end

def audited_columns

def audited_columns
  self.class.audited_columns
end

def auditing_enabled

def auditing_enabled
  return run_conditional_check(audited_options[:if]) &&
    run_conditional_check(audited_options[:unless], matching: false) &&
    self.class.auditing_enabled
end

def auditing_enabled=(val)

def auditing_enabled=(val)
  self.class.auditing_enabled = val
end

def audits_to(version = nil)

def audits_to(version = nil)
  if version == :previous
    version = if self.audit_version
                self.audit_version - 1
              else
                previous = audits.descending.offset(1).first
                previous ? previous.version : 1
              end
  end
  audits.to_version(version)
end

def combine_audits(audits_to_combine)

Combine multiple audits into one.
def combine_audits(audits_to_combine)
  combine_target = audits_to_combine.last
  combine_target.audited_changes = audits_to_combine.pluck(:audited_changes).reduce(&:merge)
  combine_target.comment = "#{combine_target.comment}\nThis audit is the result of multiple audits being combined."
  transaction do
    combine_target.save!
    audits_to_combine.unscope(:limit).where("version < ?", combine_target.version).delete_all
  end
end

def combine_audits_if_needed

def combine_audits_if_needed
  max_audits = audited_options[:max_audits]
  if max_audits && (extra_count = audits.count - max_audits) > 0
    audits_to_combine = audits.limit(extra_count + 1)
    combine_audits(audits_to_combine)
  end
end

def comment_required_state?

def comment_required_state?
  auditing_enabled &&
    ((audited_options[:on].include?(:create) && self.new_record?) ||
    (audited_options[:on].include?(:update) && self.persisted? && self.changed?))
end

def method_missing(method_name, *args, &block)

Deprecate version attribute in favor of audit_version attribute – preparing for eventual removal.
def method_missing(method_name, *args, &block)
  if method_name == :version
    ActiveSupport::Deprecation.warn("`version` attribute has been changed to `audit_version`. This attribute will be removed.")
    audit_version
  else
    super
  end
end

def non_audited_columns

def non_audited_columns
  self.class.non_audited_columns
end

def own_and_associated_audits

Returns a list combined of record audits and associated audits.
def own_and_associated_audits
  Audited.audit_class.unscoped
  .where('(auditable_type = :type AND auditable_id = :id) OR (associated_type = :type AND associated_id = :id)',
    type: self.class.name, id: id)
  .order(created_at: :desc)
end

def presence_of_audit_comment

def presence_of_audit_comment
  if comment_required_state?
    errors.add(:audit_comment, "Comment can't be blank!") unless audit_comment.present?
  end
end

def rails_below?(rails_version)

def rails_below?(rails_version)
  Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new(rails_version)
end

def reconstruct_attributes(audits)

def reconstruct_attributes(audits)
  attributes = {}
  audits.each { |audit| attributes.merge!(audit.new_attributes) }
  attributes
end

def require_comment

def require_comment
  if auditing_enabled && audit_comment.blank?
    errors.add(:audit_comment, "Comment can't be blank!")
    return false if Rails.version.start_with?('4.')
    throw(:abort)
  end
end

def revision(version)

Returns nil for versions greater than revisions count
Get a specific revision specified by the version number, or +:previous+
def revision(version)
  if version == :previous || self.audits.last.version >= version
    revision_with Audited.audit_class.reconstruct_attributes(audits_to(version))
  end
end

def revision_at(date_or_time)

Find the oldest revision recorded prior to the date/time provided.
def revision_at(date_or_time)
  audits = self.audits.up_until(date_or_time)
  revision_with Audited.audit_class.reconstruct_attributes(audits) unless audits.empty?
end

def revision_with(attributes)

def revision_with(attributes)
  dup.tap do |revision|
    revision.id = id
    revision.send :instance_variable_set, '@attributes', self.attributes if rails_below?('4.2.0')
    revision.send :instance_variable_set, '@new_record', destroyed?
    revision.send :instance_variable_set, '@persisted', !destroyed?
    revision.send :instance_variable_set, '@readonly', false
    revision.send :instance_variable_set, '@destroyed', false
    revision.send :instance_variable_set, '@_destroyed', false
    revision.send :instance_variable_set, '@marked_for_destruction', false
    Audited.audit_class.assign_revision_attributes(revision, attributes)
    # Remove any association proxies so that they will be recreated
    # and reference the correct object for this revision. The only way
    # to determine if an instance variable is a proxy object is to
    # see if it responds to certain methods, as it forwards almost
    # everything to its target.
    revision.instance_variables.each do |ivar|
      proxy = revision.instance_variable_get ivar
      if !proxy.nil? && proxy.respond_to?(:proxy_respond_to?)
        revision.instance_variable_set ivar, nil
      end
    end
  end
end

def revisions(from_version = 1)


end
user.version
user.name
user.revisions.each do |revision|

Gets an array of the revisions available
def revisions(from_version = 1)
  return [] unless audits.from_version(from_version).exists?
  all_audits = audits.select([:audited_changes, :version]).to_a
  targeted_audits = all_audits.select { |audit| audit.version >= from_version }
  previous_attributes = reconstruct_attributes(all_audits - targeted_audits)
  targeted_audits.map do |audit|
    previous_attributes.merge!(audit.new_attributes)
    revision_with(previous_attributes.merge!(version: audit.version))
  end
end

def run_conditional_check(condition, matching: true)

def run_conditional_check(condition, matching: true)
  return true if condition.blank?
  return condition.call(self) == matching if condition.respond_to?(:call)
  return send(condition) == matching if respond_to?(condition.to_sym, true)
  true
end

def save_without_auditing

Temporarily turns off auditing while saving.
def save_without_auditing
  without_auditing { save }
end

def without_auditing(&block)


end
@foo.save
@foo.without_auditing do

Executes the block with the auditing callbacks disabled.
def without_auditing(&block)
  self.class.without_auditing(&block)
end

def write_audit(attrs)

def write_audit(attrs)
  attrs[:associated] = send(audit_associated_with) unless audit_associated_with.nil?
  self.audit_comment = nil
  if auditing_enabled
    run_callbacks(:audit) {
      audit = audits.create(attrs)
      combine_audits_if_needed if attrs[:action] != 'create'
      audit
    }
  end
end