Skip to content

Commit

Permalink
Define audit_class per model
Browse files Browse the repository at this point in the history
  • Loading branch information
kuldeepaggarwal committed Nov 29, 2022
1 parent 39d29e2 commit 7d9b0d6
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 28 deletions.
43 changes: 26 additions & 17 deletions lib/audited/audit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,39 @@ module Audited
#

class YAMLIfTextColumnType
class << self
def load(obj)
if text_column?
ActiveRecord::Coders::YAMLColumn.new(Object).load(obj)
else
obj
end
end
def initialize(model)
@model = model
end

def dump(obj)
if text_column?
ActiveRecord::Coders::YAMLColumn.new(Object).dump(obj)
else
obj
end
def load(obj)
if text_column?
ActiveRecord::Coders::YAMLColumn.new(Object).load(obj)
else
obj
end
end

def text_column?
Audited.audit_class.columns_hash["audited_changes"].type.to_s == "text"
def dump(obj)
if text_column?
ActiveRecord::Coders::YAMLColumn.new(Object).dump(obj)
else
obj
end
end

private

def text_column?
@model.columns_hash["audited_changes"].type.to_s == "text"
end
end

class Audit < ::ActiveRecord::Base
def self.inherited(klass)
super
klass.serialize :audited_changes, YAMLIfTextColumnType.new(klass)
end

belongs_to :auditable, polymorphic: true
belongs_to :user, polymorphic: true
belongs_to :associated, polymorphic: true
Expand All @@ -49,7 +58,7 @@ class Audit < ::ActiveRecord::Base
cattr_accessor :audited_class_names
self.audited_class_names = Set.new

serialize :audited_changes, YAMLIfTextColumnType
serialize :audited_changes, YAMLIfTextColumnType.new(self)

scope :ascending, -> { reorder(version: :asc) }
scope :descending, -> { reorder(version: :desc) }
Expand Down
29 changes: 20 additions & 9 deletions lib/audited/auditor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ module Auditor #:nodoc:
CALLBACKS = [:audit_create, :audit_update, :audit_destroy]

module ClassMethods
def audit_class
audit_class_name&.safe_constantize || Audited.audit_class
end

# == Configuration options
#
#
Expand Down Expand Up @@ -67,20 +71,23 @@ def audited(options = {})

class_attribute :audit_associated_with, instance_writer: false
class_attribute :audited_options, instance_writer: false
class_attribute :audit_class_name, instance_writer: false

attr_accessor :audit_version, :audit_comment

self.audited_options = options
normalize_audited_options

self.audit_associated_with = audited_options[:associated_with]
self.audit_class_name = audited_options[:audit_class_name]

if audited_options[:comment_required]
validate :presence_of_audit_comment
before_destroy :require_comment if audited_options[:on].include?(:destroy)
end

has_many :audits, -> { order(version: :asc) }, as: :auditable, class_name: Audited.audit_class.name, inverse_of: :auditable
Audited.audit_class.audited_class_names << to_s
has_many :audits, -> { order(version: :asc) }, as: :auditable, class_name: audit_class.name, inverse_of: :auditable
audit_class.audited_class_names << to_s

after_create :audit_create if audited_options[:on].include?(:create)
before_update :audit_update if audited_options[:on].include?(:update)
Expand All @@ -96,14 +103,18 @@ def audited(options = {})
enable_auditing
end

def has_associated_audits
has_many :associated_audits, as: :associated, class_name: Audited.audit_class.name
def has_associated_audits(audit_class_name: Audited.audit_class.name)
has_many :associated_audits, as: :associated, class_name: audit_class_name
end
end

module AuditedInstanceMethods
REDACTED = "[REDACTED]"

def audit_class
self.class.audit_class
end

# Temporarily turns off auditing while saving.
def save_without_auditing
without_auditing { save }
Expand Down Expand Up @@ -159,14 +170,14 @@ def revisions(from_version = 1)
# Returns nil for versions greater than revisions count
def revision(version)
if version == :previous || audits.last.version >= version
revision_with Audited.audit_class.reconstruct_attributes(audits_to(version))
revision_with audit_class.reconstruct_attributes(audits_to(version))
end
end

# 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?
revision_with audit_class.reconstruct_attributes(audits) unless audits.empty?
end

# List of attributes that are audited.
Expand All @@ -177,7 +188,7 @@ def audited_attributes

# Returns a list combined of record audits and associated audits.
def own_and_associated_audits
Audited.audit_class.unscoped
audit_class.unscoped
.where("(auditable_type = :type AND auditable_id = :id) OR (associated_type = :type AND associated_id = :id)",
type: self.class.base_class.name, id: id)
.order(created_at: :desc)
Expand Down Expand Up @@ -206,7 +217,7 @@ def revision_with(attributes)
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)
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
Expand Down Expand Up @@ -431,7 +442,7 @@ def enable_auditing
# convenience wrapper around
# @see Audit#as_user.
def audit_as(user, &block)
Audited.audit_class.as_user(user, &block)
audit_class.as_user(user, &block)
end

def auditing_enabled
Expand Down
2 changes: 1 addition & 1 deletion lib/audited/rspec_matchers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def reflection
def association_exists?
!reflection.nil? &&
reflection.macro == :has_many &&
reflection.options[:class_name] == Audited.audit_class.name
reflection.options[:class_name] == model_class.audit_class.name
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/audited/audit_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class Models::ActiveRecord::CustomUserSubclass < Models::ActiveRecord::CustomUse
end

it "does not unserialize from binary columns" do
allow(Audited::YAMLIfTextColumnType).to receive(:text_column?).and_return(false)
allow_any_instance_of(Audited::YAMLIfTextColumnType).to receive(:text_column?).and_return(false)
audit.audited_changes = {foo: "bar"}
expect(audit.audited_changes).to eq "{:foo=>\"bar\"}"
end
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

Dir[SPEC_ROOT.join("support/*.rb")].sort.each { |f| require f }

ActiveRecord.use_yaml_unsafe_load = true
RSpec.configure do |config|
config.include AuditedSpecHelpers
config.use_transactional_fixtures = false if Rails.version.start_with?("4.")
Expand Down

0 comments on commit 7d9b0d6

Please sign in to comment.