diff --git a/lib/audited/audit.rb b/lib/audited/audit.rb index eadd0fb0..b11c25cc 100644 --- a/lib/audited/audit.rb +++ b/lib/audited/audit.rb @@ -16,30 +16,38 @@ 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) + klass.serialize :audited_changes, YAMLIfTextColumnType.new(klass) + end + belongs_to :auditable, polymorphic: true belongs_to :user, polymorphic: true belongs_to :associated, polymorphic: true @@ -49,7 +57,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) } diff --git a/lib/audited/auditor.rb b/lib/audited/auditor.rb index d7d674fe..ac1c0de3 100644 --- a/lib/audited/auditor.rb +++ b/lib/audited/auditor.rb @@ -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 # # @@ -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) @@ -96,8 +103,8 @@ 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 @@ -159,14 +166,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. @@ -177,7 +184,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) @@ -206,7 +213,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 @@ -431,7 +438,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 diff --git a/lib/audited/rspec_matchers.rb b/lib/audited/rspec_matchers.rb index 1999068c..675b3f98 100644 --- a/lib/audited/rspec_matchers.rb +++ b/lib/audited/rspec_matchers.rb @@ -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