Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple databases #521

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 78 additions & 66 deletions lib/audited/audit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,83 @@ def dump(obj)
end
end

class Audit < ::ActiveRecord::Base
belongs_to :auditable, polymorphic: true
belongs_to :user, polymorphic: true
belongs_to :associated, polymorphic: true
module Auditable
extend ::ActiveSupport::Concern

included do
belongs_to :auditable, polymorphic: true
belongs_to :user, polymorphic: true
belongs_to :associated, polymorphic: true

before_create :set_version_number, :set_audit_user, :set_request_uuid, :set_remote_address

cattr_accessor :audited_class_names
self.audited_class_names = Set.new

serialize :audited_changes, YAMLIfTextColumnType

scope :ascending, ->{ reorder(version: :asc) }
scope :descending, ->{ reorder(version: :desc)}
scope :creates, ->{ where(action: 'create')}
scope :updates, ->{ where(action: 'update')}
scope :destroys, ->{ where(action: 'destroy')}

scope :up_until, ->(date_or_time){ where("created_at <= ?", date_or_time) }
scope :from_version, ->(version){ where('version >= ?', version) }
scope :to_version, ->(version){ where('version <= ?', version) }
scope :auditable_finder, ->(auditable_id, auditable_type){ where(auditable_id: auditable_id, auditable_type: auditable_type)}

alias_method :user_as_model, :user
alias_method :user, :user_as_string
alias_method :user_as_model=, :user=
alias_method :user=, :user_as_string=
end

before_create :set_version_number, :set_audit_user, :set_request_uuid, :set_remote_address
class_methods do
# Returns the list of classes that are being audited
def audited_classes
audited_class_names.map(&:constantize)
end

# All audits made during the block called will be recorded as made
# by +user+. This method is hopefully threadsafe, making it ideal
# for background operations that require audit information.
def as_user(user)
last_audited_user = ::Audited.store[:audited_user]
::Audited.store[:audited_user] = user
yield
ensure
::Audited.store[:audited_user] = last_audited_user
end

cattr_accessor :audited_class_names
self.audited_class_names = Set.new
# @private
def reconstruct_attributes(audits)
audits.each_with_object({}) do |audit, all|
all.merge!(audit.new_attributes)
all[:audit_version] = audit.version
end
end

serialize :audited_changes, YAMLIfTextColumnType
# @private
def assign_revision_attributes(record, attributes)
attributes.each do |attr, val|
record = record.dup if record.frozen?

scope :ascending, ->{ reorder(version: :asc) }
scope :descending, ->{ reorder(version: :desc)}
scope :creates, ->{ where(action: 'create')}
scope :updates, ->{ where(action: 'update')}
scope :destroys, ->{ where(action: 'destroy')}
if record.respond_to?("#{attr}=")
record.attributes.key?(attr.to_s) ?
record[attr] = val :
record.send("#{attr}=", val)
end
end
record
end

# use created_at as timestamp cache key
def collection_cache_key(collection = all, *)
super(collection, :created_at)
end
end

scope :up_until, ->(date_or_time){ where("created_at <= ?", date_or_time) }
scope :from_version, ->(version){ where('version >= ?', version) }
scope :to_version, ->(version){ where('version <= ?', version) }
scope :auditable_finder, ->(auditable_id, auditable_type){ where(auditable_id: auditable_id, auditable_type: auditable_type)}
# Return all audits older than the current one.
def ancestors
self.class.ascending.auditable_finder(auditable_id, auditable_type).to_version(version)
Expand Down Expand Up @@ -109,61 +164,14 @@ 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
self.user_as_model = user :
self.username = user
end
alias_method :user_as_model=, :user=
alias_method :user=, :user_as_string=

# @private
def user_as_string
user_as_model || username
end
alias_method :user_as_model, :user
alias_method :user, :user_as_string

# Returns the list of classes that are being audited
def self.audited_classes
audited_class_names.map(&:constantize)
end

# All audits made during the block called will be recorded as made
# by +user+. This method is hopefully threadsafe, making it ideal
# for background operations that require audit information.
def self.as_user(user)
last_audited_user = ::Audited.store[:audited_user]
::Audited.store[:audited_user] = user
yield
ensure
::Audited.store[:audited_user] = last_audited_user
end

# @private
def self.reconstruct_attributes(audits)
audits.each_with_object({}) do |audit, all|
all.merge!(audit.new_attributes)
all[:audit_version] = audit.version
end
end

# @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

# use created_at as timestamp cache key
def self.collection_cache_key(collection = all, *)
super(collection, :created_at)
end

private

Expand Down Expand Up @@ -191,4 +199,8 @@ def set_remote_address
self.remote_address ||= ::Audited.store[:current_remote_address]
end
end

class Audit < ::ActiveRecord::Base
include Auditable
end
end