audited-hp 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +32 -0
- data/.yardopts +3 -0
- data/Appraisals +22 -0
- data/CHANGELOG +153 -0
- data/Gemfile +3 -0
- data/LICENSE +19 -0
- data/README.md +299 -0
- data/Rakefile +18 -0
- data/gemfiles/rails40.gemfile +9 -0
- data/gemfiles/rails41.gemfile +8 -0
- data/gemfiles/rails42.gemfile +8 -0
- data/gemfiles/rails50.gemfile +8 -0
- data/lib/audited-rspec.rb +4 -0
- data/lib/audited.rb +29 -0
- data/lib/audited/audit.rb +149 -0
- data/lib/audited/auditor.rb +309 -0
- data/lib/audited/rspec_matchers.rb +177 -0
- data/lib/audited/sweeper.rb +60 -0
- data/lib/audited/version.rb +3 -0
- data/lib/generators/audited/install_generator.rb +20 -0
- data/lib/generators/audited/migration.rb +15 -0
- data/lib/generators/audited/templates/add_association_to_audits.rb +11 -0
- data/lib/generators/audited/templates/add_comment_to_audits.rb +9 -0
- data/lib/generators/audited/templates/add_remote_address_to_audits.rb +10 -0
- data/lib/generators/audited/templates/add_request_uuid_to_audits.rb +10 -0
- data/lib/generators/audited/templates/install.rb +30 -0
- data/lib/generators/audited/templates/rename_association_to_associated.rb +23 -0
- data/lib/generators/audited/templates/rename_changes_to_audited_changes.rb +9 -0
- data/lib/generators/audited/templates/rename_parent_to_association.rb +11 -0
- data/lib/generators/audited/upgrade_generator.rb +57 -0
- data/spec/audited/audit_spec.rb +199 -0
- data/spec/audited/auditor_spec.rb +607 -0
- data/spec/audited/sweeper_spec.rb +106 -0
- data/spec/audited_spec_helpers.rb +20 -0
- data/spec/rails_app/config/application.rb +8 -0
- data/spec/rails_app/config/database.yml +24 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +21 -0
- data/spec/rails_app/config/environments/production.rb +35 -0
- data/spec/rails_app/config/environments/test.rb +47 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/inflections.rb +2 -0
- data/spec/rails_app/config/initializers/secret_token.rb +3 -0
- data/spec/rails_app/config/routes.rb +3 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/active_record/models.rb +99 -0
- data/spec/support/active_record/schema.rb +81 -0
- data/test/db/version_1.rb +17 -0
- data/test/db/version_2.rb +18 -0
- data/test/db/version_3.rb +19 -0
- data/test/db/version_4.rb +20 -0
- data/test/db/version_5.rb +18 -0
- data/test/db/version_6.rb +17 -0
- data/test/install_generator_test.rb +17 -0
- data/test/test_helper.rb +19 -0
- data/test/upgrade_generator_test.rb +77 -0
- metadata +229 -0
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require 'bundler/gem_helper'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'appraisal'
|
7
|
+
|
8
|
+
Bundler::GemHelper.install_tasks(name: 'audited')
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new(:spec)
|
11
|
+
|
12
|
+
Rake::TestTask.new do |t|
|
13
|
+
t.libs << "test"
|
14
|
+
t.test_files = FileList['test/**/*_test.rb']
|
15
|
+
t.verbose = true
|
16
|
+
end
|
17
|
+
|
18
|
+
task default: [:spec, :test]
|
data/lib/audited.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rails/observers/active_model/active_model'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
module Audited
|
5
|
+
class << self
|
6
|
+
attr_accessor :ignored_attributes, :current_user_method
|
7
|
+
|
8
|
+
# Deprecate audit_class accessors in preperation of their removal
|
9
|
+
def audit_class
|
10
|
+
Audited::Audit
|
11
|
+
end
|
12
|
+
deprecate audit_class: "Audited.audit_class is now always Audited::Audit. This method will be removed."
|
13
|
+
|
14
|
+
def store
|
15
|
+
Thread.current[:audited_store] ||= {}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
@ignored_attributes = %w(lock_version created_at updated_at created_on updated_on)
|
20
|
+
|
21
|
+
@current_user_method = :current_user
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'audited/auditor'
|
25
|
+
require 'audited/audit'
|
26
|
+
|
27
|
+
::ActiveRecord::Base.send :include, Audited::Auditor
|
28
|
+
|
29
|
+
require 'audited/sweeper'
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Audited
|
4
|
+
# Audit saves the changes to ActiveRecord models. It has the following attributes:
|
5
|
+
#
|
6
|
+
# * <tt>auditable</tt>: the ActiveRecord model that was changed
|
7
|
+
# * <tt>user</tt>: the user that performed the change; a string or an ActiveRecord model
|
8
|
+
# * <tt>action</tt>: one of create, update, or delete
|
9
|
+
# * <tt>audited_changes</tt>: a serialized hash of all the changes
|
10
|
+
# * <tt>comment</tt>: a comment set with the audit
|
11
|
+
# * <tt>version</tt>: the version of the model
|
12
|
+
# * <tt>request_uuid</tt>: a uuid based that allows audits from the same controller request
|
13
|
+
# * <tt>created_at</tt>: Time that the change was performed
|
14
|
+
#
|
15
|
+
class Audit < ::ActiveRecord::Base
|
16
|
+
include ActiveModel::Observing
|
17
|
+
|
18
|
+
belongs_to :auditable, polymorphic: true
|
19
|
+
belongs_to :user, polymorphic: true
|
20
|
+
belongs_to :associated, polymorphic: true
|
21
|
+
|
22
|
+
before_create :set_version_number, :set_audit_user, :set_request_uuid
|
23
|
+
|
24
|
+
cattr_accessor :audited_class_names
|
25
|
+
self.audited_class_names = Set.new
|
26
|
+
|
27
|
+
serialize :audited_changes
|
28
|
+
|
29
|
+
scope :ascending, ->{ reorder(version: :asc) }
|
30
|
+
scope :descending, ->{ reorder(version: :desc)}
|
31
|
+
scope :creates, ->{ where(action: 'create')}
|
32
|
+
scope :updates, ->{ where(action: 'update')}
|
33
|
+
scope :destroys, ->{ where(action: 'destroy')}
|
34
|
+
|
35
|
+
scope :up_until, ->(date_or_time){ where("created_at <= ?", date_or_time) }
|
36
|
+
scope :from_version, ->(version){ where('version >= ?', version) }
|
37
|
+
scope :to_version, ->(version){ where('version <= ?', version) }
|
38
|
+
scope :auditable_finder, ->(auditable_id, auditable_type){ where(auditable_id: auditable_id, auditable_type: auditable_type)}
|
39
|
+
# Return all audits older than the current one.
|
40
|
+
def ancestors
|
41
|
+
self.class.ascending.auditable_finder(auditable_id, auditable_type).to_version(version)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return an instance of what the object looked like at this revision. If
|
45
|
+
# the object has been destroyed, this will be a new record.
|
46
|
+
def revision
|
47
|
+
clazz = auditable_type.constantize
|
48
|
+
(clazz.find_by_id(auditable_id) || clazz.new).tap do |m|
|
49
|
+
self.class.assign_revision_attributes(m, self.class.reconstruct_attributes(ancestors).merge(version: version))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns a hash of the changed attributes with the new values
|
54
|
+
def new_attributes
|
55
|
+
(audited_changes || {}).inject({}.with_indifferent_access) do |attrs, (attr, values)|
|
56
|
+
attrs[attr] = values.is_a?(Array) ? values.last : values
|
57
|
+
attrs
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns a hash of the changed attributes with the old values
|
62
|
+
def old_attributes
|
63
|
+
(audited_changes || {}).inject({}.with_indifferent_access) do |attrs, (attr, values)|
|
64
|
+
attrs[attr] = Array(values).first
|
65
|
+
|
66
|
+
attrs
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Allows user to be set to either a string or an ActiveRecord object
|
71
|
+
# @private
|
72
|
+
def user_as_string=(user)
|
73
|
+
# reset both either way
|
74
|
+
self.user_as_model = self.username = nil
|
75
|
+
user.is_a?(::ActiveRecord::Base) ?
|
76
|
+
self.user_as_model = user :
|
77
|
+
self.username = user
|
78
|
+
end
|
79
|
+
alias_method :user_as_model=, :user=
|
80
|
+
alias_method :user=, :user_as_string=
|
81
|
+
|
82
|
+
# @private
|
83
|
+
def user_as_string
|
84
|
+
user_as_model || username
|
85
|
+
end
|
86
|
+
alias_method :user_as_model, :user
|
87
|
+
alias_method :user, :user_as_string
|
88
|
+
|
89
|
+
# Returns the list of classes that are being audited
|
90
|
+
def self.audited_classes
|
91
|
+
audited_class_names.map(&:constantize)
|
92
|
+
end
|
93
|
+
|
94
|
+
# All audits made during the block called will be recorded as made
|
95
|
+
# by +user+. This method is hopefully threadsafe, making it ideal
|
96
|
+
# for background operations that require audit information.
|
97
|
+
def self.as_user(user, &block)
|
98
|
+
Thread.current[:audited_user] = user
|
99
|
+
yield
|
100
|
+
ensure
|
101
|
+
Thread.current[:audited_user] = nil
|
102
|
+
end
|
103
|
+
|
104
|
+
# @private
|
105
|
+
def self.reconstruct_attributes(audits)
|
106
|
+
attributes = {}
|
107
|
+
result = audits.collect do |audit|
|
108
|
+
attributes.merge!(audit.new_attributes)[:version] = audit.version
|
109
|
+
yield attributes if block_given?
|
110
|
+
end
|
111
|
+
block_given? ? result : attributes
|
112
|
+
end
|
113
|
+
|
114
|
+
# @private
|
115
|
+
def self.assign_revision_attributes(record, attributes)
|
116
|
+
attributes.each do |attr, val|
|
117
|
+
record = record.dup if record.frozen?
|
118
|
+
|
119
|
+
if record.respond_to?("#{attr}=")
|
120
|
+
record.attributes.key?(attr.to_s) ?
|
121
|
+
record[attr] = val :
|
122
|
+
record.send("#{attr}=", val)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
record
|
126
|
+
end
|
127
|
+
|
128
|
+
# use created_at as timestamp cache key
|
129
|
+
def self.collection_cache_key(collection = all, timestamp_column = :created_at)
|
130
|
+
super(collection, :created_at)
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def set_version_number
|
136
|
+
max = self.class.auditable_finder(auditable_id, auditable_type).descending.first.try(:version) || 0
|
137
|
+
self.version = max + 1
|
138
|
+
end
|
139
|
+
|
140
|
+
def set_audit_user
|
141
|
+
self.user = Thread.current[:audited_user] if Thread.current[:audited_user]
|
142
|
+
nil # prevent stopping callback chains
|
143
|
+
end
|
144
|
+
|
145
|
+
def set_request_uuid
|
146
|
+
self.request_uuid ||= SecureRandom.uuid
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,309 @@
|
|
1
|
+
module Audited
|
2
|
+
# Specify this act if you want changes to your model to be saved in an
|
3
|
+
# audit table. This assumes there is an audits table ready.
|
4
|
+
#
|
5
|
+
# class User < ActiveRecord::Base
|
6
|
+
# acts_at_audited
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
# To store an audit comment set model.audit_comment to your comment before
|
10
|
+
# a create, update or destroy operation.
|
11
|
+
#
|
12
|
+
# See <tt>Audited::Auditor::ClassMethods#audited</tt>
|
13
|
+
# for configuration options
|
14
|
+
module Auditor #:nodoc:
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
|
17
|
+
CALLBACKS = [:audit_create, :audit_update, :audit_destroy]
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
# == Configuration options
|
21
|
+
#
|
22
|
+
#
|
23
|
+
# * +only+ - Only audit the given attributes
|
24
|
+
# * +except+ - Excludes fields from being saved in the audit log.
|
25
|
+
# By default, Audited will audit all but these fields:
|
26
|
+
#
|
27
|
+
# [self.primary_key, inheritance_column, 'lock_version', 'created_at', 'updated_at']
|
28
|
+
# You can add to those by passing one or an array of fields to skip.
|
29
|
+
#
|
30
|
+
# class User < ActiveRecord::Base
|
31
|
+
# audited except: :password
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# * +require_comment+ - Ensures that audit_comment is supplied before
|
35
|
+
# any create, update or destroy operation.
|
36
|
+
#
|
37
|
+
def acts_as_audited(options = {})
|
38
|
+
# don't allow multiple calls
|
39
|
+
return if included_modules.include?(Audited::Auditor::AuditedInstanceMethods)
|
40
|
+
|
41
|
+
class_attribute :audit_associated_with, instance_writer: false
|
42
|
+
class_attribute :audited_options, instance_writer: false
|
43
|
+
|
44
|
+
self.audited_options = options
|
45
|
+
self.audit_associated_with = options[:associated_with]
|
46
|
+
|
47
|
+
if options[:comment_required]
|
48
|
+
validates_presence_of :audit_comment, if: :auditing_enabled
|
49
|
+
before_destroy :require_comment
|
50
|
+
end
|
51
|
+
|
52
|
+
attr_accessor :audit_comment
|
53
|
+
|
54
|
+
has_many :audits, -> { order(version: :asc) }, as: :auditable, class_name: Audit.name
|
55
|
+
Audit.audited_class_names << to_s
|
56
|
+
|
57
|
+
on = Array(options[:on])
|
58
|
+
after_create :audit_create if on.empty? || on.include?(:create)
|
59
|
+
before_update :audit_update if on.empty? || on.include?(:update)
|
60
|
+
before_destroy :audit_destroy if on.empty? || on.include?(:destroy)
|
61
|
+
|
62
|
+
# Define and set after_audit and around_audit callbacks. This might be useful if you want
|
63
|
+
# to notify a party after the audit has been created or if you want to access the newly-created
|
64
|
+
# audit.
|
65
|
+
define_callbacks :audit
|
66
|
+
set_callback :audit, :after, :after_audit, if: lambda { respond_to?(:after_audit, true) }
|
67
|
+
set_callback :audit, :around, :around_audit, if: lambda { respond_to?(:around_audit, true) }
|
68
|
+
|
69
|
+
attr_accessor :version
|
70
|
+
|
71
|
+
extend Audited::Auditor::AuditedClassMethods
|
72
|
+
include Audited::Auditor::AuditedInstanceMethods
|
73
|
+
|
74
|
+
self.auditing_enabled = true
|
75
|
+
end
|
76
|
+
|
77
|
+
def has_associated_audits
|
78
|
+
has_many :associated_audits, as: :associated, class_name: Audit.name
|
79
|
+
end
|
80
|
+
|
81
|
+
def default_ignored_attributes
|
82
|
+
[primary_key, inheritance_column]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
module AuditedInstanceMethods
|
87
|
+
# Temporarily turns off auditing while saving.
|
88
|
+
def save_without_auditing
|
89
|
+
without_auditing { save }
|
90
|
+
end
|
91
|
+
|
92
|
+
# Executes the block with the auditing callbacks disabled.
|
93
|
+
#
|
94
|
+
# @foo.without_auditing do
|
95
|
+
# @foo.save
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
def without_auditing(&block)
|
99
|
+
self.class.without_auditing(&block)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Gets an array of the revisions available
|
103
|
+
#
|
104
|
+
# user.revisions.each do |revision|
|
105
|
+
# user.name
|
106
|
+
# user.version
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
def revisions(from_version = 1)
|
110
|
+
audits = self.audits.from_version(from_version)
|
111
|
+
return [] if audits.empty?
|
112
|
+
revisions = []
|
113
|
+
audits.each do |audit|
|
114
|
+
revisions << audit.revision
|
115
|
+
end
|
116
|
+
revisions
|
117
|
+
end
|
118
|
+
|
119
|
+
# Get a specific revision specified by the version number, or +:previous+
|
120
|
+
def revision(version)
|
121
|
+
revision_with Audit.reconstruct_attributes(audits_to(version))
|
122
|
+
end
|
123
|
+
|
124
|
+
# Find the oldest revision recorded prior to the date/time provided.
|
125
|
+
def revision_at(date_or_time)
|
126
|
+
audits = self.audits.up_until(date_or_time)
|
127
|
+
revision_with Audit.reconstruct_attributes(audits) unless audits.empty?
|
128
|
+
end
|
129
|
+
|
130
|
+
# List of attributes that are audited.
|
131
|
+
def audited_attributes
|
132
|
+
attributes.except(*non_audited_columns)
|
133
|
+
end
|
134
|
+
|
135
|
+
def non_audited_columns
|
136
|
+
self.class.non_audited_columns
|
137
|
+
end
|
138
|
+
|
139
|
+
protected
|
140
|
+
|
141
|
+
def non_audited_columns
|
142
|
+
self.class.non_audited_columns
|
143
|
+
end
|
144
|
+
|
145
|
+
def revision_with(attributes)
|
146
|
+
dup.tap do |revision|
|
147
|
+
revision.id = id
|
148
|
+
revision.send :instance_variable_set, '@attributes', self.attributes if rails_below?('4.2.0')
|
149
|
+
revision.send :instance_variable_set, '@new_record', destroyed?
|
150
|
+
revision.send :instance_variable_set, '@persisted', !destroyed?
|
151
|
+
revision.send :instance_variable_set, '@readonly', false
|
152
|
+
revision.send :instance_variable_set, '@destroyed', false
|
153
|
+
revision.send :instance_variable_set, '@_destroyed', false
|
154
|
+
revision.send :instance_variable_set, '@marked_for_destruction', false
|
155
|
+
Audit.assign_revision_attributes(revision, attributes)
|
156
|
+
|
157
|
+
# Remove any association proxies so that they will be recreated
|
158
|
+
# and reference the correct object for this revision. The only way
|
159
|
+
# to determine if an instance variable is a proxy object is to
|
160
|
+
# see if it responds to certain methods, as it forwards almost
|
161
|
+
# everything to its target.
|
162
|
+
revision.instance_variables.each do |ivar|
|
163
|
+
proxy = revision.instance_variable_get ivar
|
164
|
+
if !proxy.nil? && proxy.respond_to?(:proxy_respond_to?)
|
165
|
+
revision.instance_variable_set ivar, nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def rails_below?(rails_version)
|
172
|
+
Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new(rails_version)
|
173
|
+
end
|
174
|
+
|
175
|
+
private
|
176
|
+
|
177
|
+
def audited_changes
|
178
|
+
collection =
|
179
|
+
if audited_options[:only]
|
180
|
+
audited_columns = self.class.audited_columns.map(&:name)
|
181
|
+
changed_attributes.slice(*audited_columns)
|
182
|
+
else
|
183
|
+
changed_attributes.except(*non_audited_columns)
|
184
|
+
end
|
185
|
+
|
186
|
+
collection.inject({}) do |changes, (attr, old_value)|
|
187
|
+
changes[attr] = [old_value, self[attr]]
|
188
|
+
changes
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def audits_to(version = nil)
|
193
|
+
if version == :previous
|
194
|
+
version = if self.version
|
195
|
+
self.version - 1
|
196
|
+
else
|
197
|
+
previous = audits.descending.offset(1).first
|
198
|
+
previous ? previous.version : 1
|
199
|
+
end
|
200
|
+
end
|
201
|
+
audits.to_version(version)
|
202
|
+
end
|
203
|
+
|
204
|
+
def audit_create
|
205
|
+
write_audit(action: 'create', audited_changes: audited_attributes,
|
206
|
+
comment: audit_comment)
|
207
|
+
end
|
208
|
+
|
209
|
+
def audit_update
|
210
|
+
unless (changes = audited_changes).empty? && audit_comment.blank?
|
211
|
+
write_audit(action: 'update', audited_changes: changes,
|
212
|
+
comment: audit_comment)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def audit_destroy
|
217
|
+
write_audit(action: 'destroy', audited_changes: audited_attributes,
|
218
|
+
comment: audit_comment) unless new_record?
|
219
|
+
end
|
220
|
+
|
221
|
+
def write_audit(attrs)
|
222
|
+
attrs[:associated] = send(audit_associated_with) unless audit_associated_with.nil?
|
223
|
+
self.audit_comment = nil
|
224
|
+
run_callbacks(:audit) { audits.create(attrs) } if auditing_enabled
|
225
|
+
end
|
226
|
+
|
227
|
+
def require_comment
|
228
|
+
if auditing_enabled && audit_comment.blank?
|
229
|
+
errors.add(:audit_comment, "Comment required before destruction")
|
230
|
+
return false if Rails.version.start_with?('4.')
|
231
|
+
throw :abort
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
CALLBACKS.each do |attr_name|
|
236
|
+
alias_method "#{attr_name}_callback".to_sym, attr_name
|
237
|
+
end
|
238
|
+
|
239
|
+
def empty_callback #:nodoc:
|
240
|
+
end
|
241
|
+
|
242
|
+
def auditing_enabled
|
243
|
+
self.class.auditing_enabled
|
244
|
+
end
|
245
|
+
|
246
|
+
def auditing_enabled=(val)
|
247
|
+
self.class.auditing_enabled = val
|
248
|
+
end
|
249
|
+
end # InstanceMethods
|
250
|
+
|
251
|
+
module AuditedClassMethods
|
252
|
+
# Returns an array of columns that are audited. See non_audited_columns
|
253
|
+
def audited_columns
|
254
|
+
columns.select {|c| !non_audited_columns.include?(c.name) }
|
255
|
+
end
|
256
|
+
|
257
|
+
def non_audited_columns
|
258
|
+
@non_audited_columns ||= begin
|
259
|
+
options = audited_options
|
260
|
+
if options[:only]
|
261
|
+
except = column_names - Array.wrap(options[:only]).flatten.map(&:to_s)
|
262
|
+
else
|
263
|
+
except = default_ignored_attributes + Audited.ignored_attributes
|
264
|
+
except |= Array(options[:except]).collect(&:to_s) if options[:except]
|
265
|
+
end
|
266
|
+
except
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# Executes the block with auditing disabled.
|
271
|
+
#
|
272
|
+
# Foo.without_auditing do
|
273
|
+
# @foo.save
|
274
|
+
# end
|
275
|
+
#
|
276
|
+
def without_auditing
|
277
|
+
auditing_was_enabled = auditing_enabled
|
278
|
+
disable_auditing
|
279
|
+
yield
|
280
|
+
ensure
|
281
|
+
enable_auditing if auditing_was_enabled
|
282
|
+
end
|
283
|
+
|
284
|
+
def disable_auditing
|
285
|
+
self.auditing_enabled = false
|
286
|
+
end
|
287
|
+
|
288
|
+
def enable_auditing
|
289
|
+
self.auditing_enabled = true
|
290
|
+
end
|
291
|
+
|
292
|
+
# All audit operations during the block are recorded as being
|
293
|
+
# made by +user+. This is not model specific, the method is a
|
294
|
+
# convenience wrapper around
|
295
|
+
# @see Audit#as_user.
|
296
|
+
def audit_as(user, &block)
|
297
|
+
Audit.as_user(user, &block)
|
298
|
+
end
|
299
|
+
|
300
|
+
def auditing_enabled
|
301
|
+
Audited.store.fetch("#{table_name}_auditing_enabled", true)
|
302
|
+
end
|
303
|
+
|
304
|
+
def auditing_enabled=(val)
|
305
|
+
Audited.store["#{table_name}_auditing_enabled"] = val
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|