audited 4.6.0 → 4.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of audited might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.gitignore +0 -1
- data/.rubocop.yml +25 -0
- data/.travis.yml +35 -21
- data/Appraisals +29 -12
- data/CHANGELOG.md +108 -0
- data/README.md +125 -39
- data/gemfiles/rails42.gemfile +3 -0
- data/gemfiles/rails50.gemfile +3 -0
- data/gemfiles/rails51.gemfile +3 -0
- data/gemfiles/rails52.gemfile +4 -2
- data/gemfiles/rails60.gemfile +10 -0
- data/gemfiles/rails61.gemfile +10 -0
- data/lib/audited.rb +2 -1
- data/lib/audited/audit.rb +31 -25
- data/lib/audited/auditor.rb +199 -39
- data/lib/audited/rspec_matchers.rb +70 -21
- data/lib/audited/version.rb +1 -1
- data/lib/generators/audited/templates/add_version_to_auditable_index.rb +21 -0
- data/lib/generators/audited/templates/install.rb +1 -1
- data/lib/generators/audited/upgrade_generator.rb +4 -0
- data/spec/audited/audit_spec.rb +88 -21
- data/spec/audited/auditor_spec.rb +450 -57
- data/spec/audited/rspec_matchers_spec.rb +69 -0
- data/spec/audited/sweeper_spec.rb +15 -6
- data/spec/audited_spec_helpers.rb +16 -2
- data/spec/rails_app/app/assets/config/manifest.js +1 -0
- data/spec/rails_app/app/controllers/application_controller.rb +2 -0
- data/spec/rails_app/config/application.rb +5 -0
- data/spec/rails_app/config/database.yml +1 -0
- data/spec/spec_helper.rb +4 -1
- data/spec/support/active_record/models.rb +50 -3
- data/spec/support/active_record/schema.rb +4 -2
- data/test/db/version_6.rb +2 -0
- data/test/test_helper.rb +1 -2
- data/test/upgrade_generator_test.rb +10 -0
- metadata +60 -22
- data/gemfiles/rails40.gemfile +0 -9
- data/gemfiles/rails41.gemfile +0 -8
@@ -41,12 +41,12 @@ module Audited
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def only(*fields)
|
44
|
-
@options[:only] = fields.flatten
|
44
|
+
@options[:only] = fields.flatten.map(&:to_s)
|
45
45
|
self
|
46
46
|
end
|
47
47
|
|
48
48
|
def except(*fields)
|
49
|
-
@options[:except] = fields.flatten
|
49
|
+
@options[:except] = fields.flatten.map(&:to_s)
|
50
50
|
self
|
51
51
|
end
|
52
52
|
|
@@ -56,16 +56,13 @@ module Audited
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def on(*actions)
|
59
|
-
@options[:on] = actions.flatten
|
59
|
+
@options[:on] = actions.flatten.map(&:to_sym)
|
60
60
|
self
|
61
61
|
end
|
62
62
|
|
63
63
|
def matches?(subject)
|
64
64
|
@subject = subject
|
65
|
-
auditing_enabled? &&
|
66
|
-
associated_with_model? &&
|
67
|
-
records_changes_to_specified_fields? &&
|
68
|
-
comment_required_valid?
|
65
|
+
auditing_enabled? && required_checks_for_options_satisfied?
|
69
66
|
end
|
70
67
|
|
71
68
|
def failure_message
|
@@ -109,31 +106,83 @@ module Audited
|
|
109
106
|
end
|
110
107
|
|
111
108
|
def records_changes_to_specified_fields?
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
109
|
+
ignored_fields = build_ignored_fields_from_options
|
110
|
+
|
111
|
+
expects "non audited columns (#{model_class.non_audited_columns.inspect}) to match (#{ignored_fields})"
|
112
|
+
model_class.non_audited_columns.to_set == ignored_fields.to_set
|
113
|
+
end
|
114
|
+
|
115
|
+
def comment_required_valid?
|
116
|
+
expects "to require audit_comment before #{model_class.audited_options[:on]} when comment required"
|
117
|
+
validate_callbacks_include_presence_of_comment? && destroy_callbacks_include_comment_required?
|
118
|
+
end
|
119
119
|
|
120
|
-
|
121
|
-
|
120
|
+
def only_audit_on_designated_callbacks?
|
121
|
+
{
|
122
|
+
create: [:after, :audit_create],
|
123
|
+
update: [:before, :audit_update],
|
124
|
+
destroy: [:before, :audit_destroy]
|
125
|
+
}.map do |(action, kind_callback)|
|
126
|
+
kind, callback = kind_callback
|
127
|
+
callbacks_for(action, kind: kind).include?(callback) if @options[:on].include?(action)
|
128
|
+
end.compact.all?
|
129
|
+
end
|
130
|
+
|
131
|
+
def validate_callbacks_include_presence_of_comment?
|
132
|
+
if @options[:comment_required] && audited_on_create_or_update?
|
133
|
+
callbacks_for(:validate).include?(:presence_of_audit_comment)
|
122
134
|
else
|
123
135
|
true
|
124
136
|
end
|
125
137
|
end
|
126
138
|
|
127
|
-
def
|
128
|
-
|
129
|
-
|
139
|
+
def audited_on_create_or_update?
|
140
|
+
model_class.audited_options[:on].include?(:create) || model_class.audited_options[:on].include?(:update)
|
141
|
+
end
|
130
142
|
|
131
|
-
|
132
|
-
|
143
|
+
def destroy_callbacks_include_comment_required?
|
144
|
+
if @options[:comment_required] && model_class.audited_options[:on].include?(:destroy)
|
145
|
+
callbacks_for(:destroy).include?(:require_comment)
|
133
146
|
else
|
134
147
|
true
|
135
148
|
end
|
136
149
|
end
|
150
|
+
|
151
|
+
def requires_comment_before_callbacks?
|
152
|
+
[:create, :update, :destroy].map do |action|
|
153
|
+
if @options[:comment_required] && model_class.audited_options[:on].include?(action)
|
154
|
+
callbacks_for(action).include?(:require_comment)
|
155
|
+
end
|
156
|
+
end.compact.all?
|
157
|
+
end
|
158
|
+
|
159
|
+
def callbacks_for(action, kind: :before)
|
160
|
+
model_class.send("_#{action}_callbacks").select { |cb| cb.kind == kind }.map(&:filter)
|
161
|
+
end
|
162
|
+
|
163
|
+
def build_ignored_fields_from_options
|
164
|
+
default_ignored_attributes = model_class.default_ignored_attributes
|
165
|
+
|
166
|
+
if @options[:only].present?
|
167
|
+
(default_ignored_attributes | model_class.column_names) - @options[:only]
|
168
|
+
elsif @options[:except].present?
|
169
|
+
default_ignored_attributes | @options[:except]
|
170
|
+
else
|
171
|
+
default_ignored_attributes
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def required_checks_for_options_satisfied?
|
176
|
+
{
|
177
|
+
only: :records_changes_to_specified_fields?,
|
178
|
+
except: :records_changes_to_specified_fields?,
|
179
|
+
comment_required: :comment_required_valid?,
|
180
|
+
associated_with: :associated_with_model?,
|
181
|
+
on: :only_audit_on_designated_callbacks?
|
182
|
+
}.map do |(option, check)|
|
183
|
+
send(check) if @options[option].present?
|
184
|
+
end.compact.all?
|
185
|
+
end
|
137
186
|
end
|
138
187
|
|
139
188
|
class AssociatedAuditMatcher # :nodoc:
|
data/lib/audited/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
class <%= migration_class_name %> < <%= migration_parent %>
|
2
|
+
def self.up
|
3
|
+
if index_exists?(:audits, [:auditable_type, :auditable_id], name: index_name)
|
4
|
+
remove_index :audits, name: index_name
|
5
|
+
add_index :audits, [:auditable_type, :auditable_id, :version], name: index_name
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.down
|
10
|
+
if index_exists?(:audits, [:auditable_type, :auditable_id, :version], name: index_name)
|
11
|
+
remove_index :audits, name: index_name
|
12
|
+
add_index :audits, [:auditable_type, :auditable_id], name: index_name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def index_name
|
19
|
+
'auditable_index'
|
20
|
+
end
|
21
|
+
end
|
@@ -17,7 +17,7 @@ class <%= migration_class_name %> < <%= migration_parent %>
|
|
17
17
|
t.column :created_at, :datetime
|
18
18
|
end
|
19
19
|
|
20
|
-
add_index :audits, [:auditable_type, :auditable_id], :name => 'auditable_index'
|
20
|
+
add_index :audits, [:auditable_type, :auditable_id, :version], :name => 'auditable_index'
|
21
21
|
add_index :audits, [:associated_type, :associated_id], :name => 'associated_index'
|
22
22
|
add_index :audits, [:user_id, :user_type], :name => 'user_index'
|
23
23
|
add_index :audits, :request_uuid
|
@@ -58,6 +58,10 @@ module Audited
|
|
58
58
|
if indexes.any? { |i| i.columns == %w[associated_id associated_type] }
|
59
59
|
yield :revert_polymorphic_indexes_order
|
60
60
|
end
|
61
|
+
|
62
|
+
if indexes.any? { |i| i.columns == %w[auditable_type auditable_id] }
|
63
|
+
yield :add_version_to_auditable_index
|
64
|
+
end
|
61
65
|
end
|
62
66
|
end
|
63
67
|
end
|
data/spec/audited/audit_spec.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
+
SingleCov.covered! uncovered: 1 # Rails version check
|
4
|
+
|
3
5
|
describe Audited::Audit do
|
4
6
|
let(:user) { Models::ActiveRecord::User.new name: "Testing" }
|
5
7
|
|
@@ -38,43 +40,64 @@ describe Audited::Audit do
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
+
context "when a custom audit class is not configured" do
|
44
|
+
it "should default to #{described_class}" do
|
45
|
+
TempModel.audited
|
46
|
+
|
47
|
+
record = TempModel.create
|
48
|
+
|
49
|
+
audit = record.audits.first
|
50
|
+
expect(audit).to be_a Audited::Audit
|
51
|
+
expect(audit.respond_to?(:custom_method)).to be false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#audited_changes" do
|
57
|
+
let(:audit) { Audited.audit_class.new }
|
58
|
+
|
59
|
+
it "can unserialize yaml from text columns" do
|
60
|
+
audit.audited_changes = {foo: "bar"}
|
61
|
+
expect(audit.audited_changes).to eq foo: "bar"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "does not unserialize from binary columns" do
|
65
|
+
allow(Audited::YAMLIfTextColumnType).to receive(:text_column?).and_return(false)
|
66
|
+
audit.audited_changes = {foo: "bar"}
|
67
|
+
expect(audit.audited_changes).to eq "{:foo=>\"bar\"}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#undo" do
|
72
|
+
let(:user) { Models::ActiveRecord::User.create(name: "John") }
|
73
|
+
|
74
|
+
it "undos changes" do
|
43
75
|
user.update_attribute(:name, 'Joe')
|
44
76
|
user.audits.last.undo
|
45
77
|
user.reload
|
46
|
-
|
47
78
|
expect(user.name).to eq("John")
|
48
79
|
end
|
49
80
|
|
50
|
-
it "
|
51
|
-
user = Models::ActiveRecord::User.create(name: "John")
|
81
|
+
it "undos destroy" do
|
52
82
|
user.destroy
|
53
83
|
user.audits.last.undo
|
54
84
|
user = Models::ActiveRecord::User.find_by(name: "John")
|
55
85
|
expect(user.name).to eq("John")
|
56
86
|
end
|
57
87
|
|
58
|
-
it "
|
59
|
-
user
|
88
|
+
it "undos creation" do
|
89
|
+
user # trigger create
|
60
90
|
expect {user.audits.last.undo}.to change(Models::ActiveRecord::User, :count).by(-1)
|
61
91
|
end
|
62
92
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
record = TempModel.create
|
68
|
-
|
69
|
-
audit = record.audits.first
|
70
|
-
expect(audit).to be_a Audited::Audit
|
71
|
-
expect(audit.respond_to?(:custom_method)).to be false
|
72
|
-
end
|
93
|
+
it "fails when trying to undo unknown" do
|
94
|
+
audit = user.audits.last
|
95
|
+
audit.action = 'oops'
|
96
|
+
expect { audit.undo }.to raise_error("invalid action given oops")
|
73
97
|
end
|
74
98
|
end
|
75
99
|
|
76
100
|
describe "user=" do
|
77
|
-
|
78
101
|
it "should be able to set the user to a model object" do
|
79
102
|
subject.user = user
|
80
103
|
expect(subject.user).to eq(user)
|
@@ -110,11 +133,9 @@ describe Audited::Audit do
|
|
110
133
|
subject.user = user
|
111
134
|
expect(subject.username).to be_nil
|
112
135
|
end
|
113
|
-
|
114
136
|
end
|
115
137
|
|
116
138
|
describe "revision" do
|
117
|
-
|
118
139
|
it "should recreate attributes" do
|
119
140
|
user = Models::ActiveRecord::User.create name: "1"
|
120
141
|
5.times {|i| user.update_attribute :name, (i + 2).to_s }
|
@@ -148,6 +169,34 @@ describe Audited::Audit do
|
|
148
169
|
end
|
149
170
|
end
|
150
171
|
|
172
|
+
describe ".collection_cache_key" do
|
173
|
+
if ActiveRecord::VERSION::MAJOR >= 5
|
174
|
+
it "uses created at" do
|
175
|
+
Audited::Audit.delete_all
|
176
|
+
audit = Models::ActiveRecord::User.create(name: "John").audits.last
|
177
|
+
audit.update_columns(created_at: Time.zone.parse('2018-01-01'))
|
178
|
+
expect(Audited::Audit.collection_cache_key).to match(/-20180101\d+$/)
|
179
|
+
end
|
180
|
+
else
|
181
|
+
it "is not defined" do
|
182
|
+
expect { Audited::Audit.collection_cache_key }.to raise_error(NoMethodError)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe ".assign_revision_attributes" do
|
188
|
+
it "dups when frozen" do
|
189
|
+
user.freeze
|
190
|
+
assigned = Audited::Audit.assign_revision_attributes(user, name: "Bar")
|
191
|
+
expect(assigned.name).to eq "Bar"
|
192
|
+
end
|
193
|
+
|
194
|
+
it "ignores unassignable attributes" do
|
195
|
+
assigned = Audited::Audit.assign_revision_attributes(user, oops: "Bar")
|
196
|
+
expect(assigned.name).to eq "Testing"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
151
200
|
it "should set the version number on create" do
|
152
201
|
user = Models::ActiveRecord::User.create! name: "Set Version Number"
|
153
202
|
expect(user.audits.first.version).to eq(1)
|
@@ -213,6 +262,25 @@ describe Audited::Audit do
|
|
213
262
|
end
|
214
263
|
end
|
215
264
|
|
265
|
+
it "should support nested as_user" do
|
266
|
+
Audited::Audit.as_user("sidekiq") do
|
267
|
+
company = Models::ActiveRecord::Company.create name: "The auditors"
|
268
|
+
company.name = "The Auditors, Inc"
|
269
|
+
company.save
|
270
|
+
expect(company.audits[-1].user).to eq("sidekiq")
|
271
|
+
|
272
|
+
Audited::Audit.as_user(user) do
|
273
|
+
company.name = "NEW Auditors, Inc"
|
274
|
+
company.save
|
275
|
+
expect(company.audits[-1].user).to eq(user)
|
276
|
+
end
|
277
|
+
|
278
|
+
company.name = "LAST Auditors, Inc"
|
279
|
+
company.save
|
280
|
+
expect(company.audits[-1].user).to eq("sidekiq")
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
216
284
|
it "should record usernames" do
|
217
285
|
Audited::Audit.as_user(user.name) do
|
218
286
|
company = Models::ActiveRecord::Company.create name: "The auditors"
|
@@ -263,6 +331,5 @@ describe Audited::Audit do
|
|
263
331
|
}.to raise_exception('expected')
|
264
332
|
expect(Audited.store[:audited_user]).to be_nil
|
265
333
|
end
|
266
|
-
|
267
334
|
end
|
268
335
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
+
SingleCov.covered! uncovered: 13 # not testing proxy_respond_to? hack / 2 methods / deprecation of `version`
|
4
|
+
|
3
5
|
describe Audited::Auditor do
|
4
6
|
|
5
7
|
describe "configuration" do
|
@@ -17,6 +19,132 @@ describe Audited::Auditor do
|
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
22
|
+
context "should be configurable which conditions are audited" do
|
23
|
+
subject { ConditionalCompany.new.send(:auditing_enabled) }
|
24
|
+
|
25
|
+
context "when condition method is private" do
|
26
|
+
subject { ConditionalPrivateCompany.new.send(:auditing_enabled) }
|
27
|
+
|
28
|
+
before do
|
29
|
+
class ConditionalPrivateCompany < ::ActiveRecord::Base
|
30
|
+
self.table_name = 'companies'
|
31
|
+
|
32
|
+
audited if: :foo?
|
33
|
+
|
34
|
+
private def foo?
|
35
|
+
true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it { is_expected.to be_truthy }
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when passing a method name" do
|
44
|
+
before do
|
45
|
+
class ConditionalCompany < ::ActiveRecord::Base
|
46
|
+
self.table_name = 'companies'
|
47
|
+
|
48
|
+
audited if: :public?
|
49
|
+
|
50
|
+
def public?; end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when conditions are true" do
|
55
|
+
before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(true) }
|
56
|
+
it { is_expected.to be_truthy }
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when conditions are false" do
|
60
|
+
before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(false) }
|
61
|
+
it { is_expected.to be_falsey }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when passing a Proc" do
|
66
|
+
context "when conditions are true" do
|
67
|
+
before do
|
68
|
+
class InclusiveCompany < ::ActiveRecord::Base
|
69
|
+
self.table_name = 'companies'
|
70
|
+
audited if: Proc.new { true }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
subject { InclusiveCompany.new.send(:auditing_enabled) }
|
75
|
+
|
76
|
+
it { is_expected.to be_truthy }
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when conditions are false" do
|
80
|
+
before do
|
81
|
+
class ExclusiveCompany < ::ActiveRecord::Base
|
82
|
+
self.table_name = 'companies'
|
83
|
+
audited if: Proc.new { false }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
subject { ExclusiveCompany.new.send(:auditing_enabled) }
|
87
|
+
it { is_expected.to be_falsey }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "should be configurable which conditions aren't audited" do
|
93
|
+
context "when using a method name" do
|
94
|
+
before do
|
95
|
+
class ExclusionaryCompany < ::ActiveRecord::Base
|
96
|
+
self.table_name = 'companies'
|
97
|
+
|
98
|
+
audited unless: :non_profit?
|
99
|
+
|
100
|
+
def non_profit?; end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
subject { ExclusionaryCompany.new.send(:auditing_enabled) }
|
105
|
+
|
106
|
+
context "when conditions are true" do
|
107
|
+
before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(true) }
|
108
|
+
it { is_expected.to be_falsey }
|
109
|
+
end
|
110
|
+
|
111
|
+
context "when conditions are false" do
|
112
|
+
before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(false) }
|
113
|
+
it { is_expected.to be_truthy }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "when using a proc" do
|
118
|
+
context "when conditions are true" do
|
119
|
+
before do
|
120
|
+
class ExclusionaryCompany < ::ActiveRecord::Base
|
121
|
+
self.table_name = 'companies'
|
122
|
+
audited unless: Proc.new { |c| c.exclusive? }
|
123
|
+
|
124
|
+
def exclusive?
|
125
|
+
true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
subject { ExclusionaryCompany.new.send(:auditing_enabled) }
|
131
|
+
it { is_expected.to be_falsey }
|
132
|
+
end
|
133
|
+
|
134
|
+
context "when conditions are false" do
|
135
|
+
before do
|
136
|
+
class InclusiveCompany < ::ActiveRecord::Base
|
137
|
+
self.table_name = 'companies'
|
138
|
+
audited unless: Proc.new { false }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
subject { InclusiveCompany.new.send(:auditing_enabled) }
|
143
|
+
it { is_expected.to be_truthy }
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
20
148
|
it "should be configurable which attributes are not audited via ignored_attributes" do
|
21
149
|
Audited.ignored_attributes = ['delta', 'top_secret', 'created_at']
|
22
150
|
class Secret < ::ActiveRecord::Base
|
@@ -36,9 +164,14 @@ describe Audited::Auditor do
|
|
36
164
|
end
|
37
165
|
|
38
166
|
it "should not save non-audited columns" do
|
39
|
-
|
167
|
+
previous = Models::ActiveRecord::User.non_audited_columns
|
168
|
+
begin
|
169
|
+
Models::ActiveRecord::User.non_audited_columns += [:favourite_device]
|
40
170
|
|
41
|
-
|
171
|
+
expect(create_user.audits.first.audited_changes.keys.any? { |col| ['favourite_device', 'created_at', 'updated_at', 'password'].include?( col ) }).to eq(false)
|
172
|
+
ensure
|
173
|
+
Models::ActiveRecord::User.non_audited_columns = previous
|
174
|
+
end
|
42
175
|
end
|
43
176
|
|
44
177
|
it "should not save other columns than specified in 'only' option" do
|
@@ -79,16 +212,49 @@ describe Audited::Auditor do
|
|
79
212
|
expect(user.audits.last.audited_changes.keys).to eq(%w{non_column_attr})
|
80
213
|
end
|
81
214
|
|
82
|
-
|
215
|
+
it "should redact columns specified in 'redacted' option" do
|
216
|
+
redacted = Audited::Auditor::AuditedInstanceMethods::REDACTED
|
217
|
+
user = Models::ActiveRecord::UserRedactedPassword.create(password: "password")
|
218
|
+
user.save!
|
219
|
+
expect(user.audits.last.audited_changes['password']).to eq(redacted)
|
220
|
+
user.password = "new_password"
|
221
|
+
user.save!
|
222
|
+
expect(user.audits.last.audited_changes['password']).to eq([redacted, redacted])
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should redact columns specified in 'redacted' option when there are multiple specified" do
|
226
|
+
redacted = Audited::Auditor::AuditedInstanceMethods::REDACTED
|
227
|
+
user =
|
228
|
+
Models::ActiveRecord::UserMultipleRedactedAttributes.create(
|
229
|
+
password: "password",
|
230
|
+
ssn: 123456789
|
231
|
+
)
|
232
|
+
user.save!
|
233
|
+
expect(user.audits.last.audited_changes['password']).to eq(redacted)
|
234
|
+
expect(user.audits.last.audited_changes['ssn']).to eq(redacted)
|
235
|
+
user.password = "new_password"
|
236
|
+
user.ssn = 987654321
|
237
|
+
user.save!
|
238
|
+
expect(user.audits.last.audited_changes['password']).to eq([redacted, redacted])
|
239
|
+
expect(user.audits.last.audited_changes['ssn']).to eq([redacted, redacted])
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should redact columns in 'redacted' column with custom option" do
|
243
|
+
user = Models::ActiveRecord::UserRedactedPasswordCustomRedaction.create(password: "password")
|
244
|
+
user.save!
|
245
|
+
expect(user.audits.last.audited_changes['password']).to eq(["My", "Custom", "Value", 7])
|
246
|
+
end
|
247
|
+
|
248
|
+
if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
83
249
|
describe "'json' and 'jsonb' audited_changes column type" do
|
84
250
|
let(:migrations_path) { SPEC_ROOT.join("support/active_record/postgres") }
|
85
251
|
|
86
252
|
after do
|
87
|
-
|
253
|
+
run_migrations(:down, migrations_path)
|
88
254
|
end
|
89
255
|
|
90
256
|
it "should work if column type is 'json'" do
|
91
|
-
|
257
|
+
run_migrations(:up, migrations_path, 1)
|
92
258
|
Audited::Audit.reset_column_information
|
93
259
|
expect(Audited::Audit.columns_hash["audited_changes"].sql_type).to eq("json")
|
94
260
|
|
@@ -99,7 +265,7 @@ describe Audited::Auditor do
|
|
99
265
|
end
|
100
266
|
|
101
267
|
it "should work if column type is 'jsonb'" do
|
102
|
-
|
268
|
+
run_migrations(:up, migrations_path, 2)
|
103
269
|
Audited::Audit.reset_column_information
|
104
270
|
expect(Audited::Audit.columns_hash["audited_changes"].sql_type).to eq("jsonb")
|
105
271
|
|
@@ -133,7 +299,7 @@ describe Audited::Auditor do
|
|
133
299
|
end
|
134
300
|
|
135
301
|
describe "on create" do
|
136
|
-
let( :user ) { create_user audit_comment: "Create" }
|
302
|
+
let( :user ) { create_user status: :reliable, audit_comment: "Create" }
|
137
303
|
|
138
304
|
it "should change the audit count" do
|
139
305
|
expect {
|
@@ -157,6 +323,10 @@ describe Audited::Auditor do
|
|
157
323
|
expect(user.audits.first.audited_changes).to eq(user.audited_attributes)
|
158
324
|
end
|
159
325
|
|
326
|
+
it "should store enum value" do
|
327
|
+
expect(user.audits.first.audited_changes["status"]).to eq(1)
|
328
|
+
end
|
329
|
+
|
160
330
|
it "should store comment" do
|
161
331
|
expect(user.audits.first.comment).to eq('Create')
|
162
332
|
end
|
@@ -175,7 +345,7 @@ describe Audited::Auditor do
|
|
175
345
|
|
176
346
|
describe "on update" do
|
177
347
|
before do
|
178
|
-
@user = create_user( name: 'Brandon', audit_comment: 'Update' )
|
348
|
+
@user = create_user( name: 'Brandon', status: :active, audit_comment: 'Update' )
|
179
349
|
end
|
180
350
|
|
181
351
|
it "should save an audit" do
|
@@ -188,17 +358,22 @@ describe Audited::Auditor do
|
|
188
358
|
end
|
189
359
|
|
190
360
|
it "should set the action to 'update'" do
|
191
|
-
@user.
|
361
|
+
@user.update! name: 'Changed'
|
192
362
|
expect(@user.audits.last.action).to eq('update')
|
193
363
|
expect(Audited::Audit.updates.order(:id).last).to eq(@user.audits.last)
|
194
364
|
expect(@user.audits.updates.last).to eq(@user.audits.last)
|
195
365
|
end
|
196
366
|
|
197
367
|
it "should store the changed attributes" do
|
198
|
-
@user.
|
368
|
+
@user.update! name: 'Changed'
|
199
369
|
expect(@user.audits.last.audited_changes).to eq({ 'name' => ['Brandon', 'Changed'] })
|
200
370
|
end
|
201
371
|
|
372
|
+
it "should store changed enum values" do
|
373
|
+
@user.update! status: 1
|
374
|
+
expect(@user.audits.last.audited_changes["status"]).to eq([0, 1])
|
375
|
+
end
|
376
|
+
|
202
377
|
it "should store audit comment" do
|
203
378
|
expect(@user.audits.last.comment).to eq('Update')
|
204
379
|
end
|
@@ -206,12 +381,12 @@ describe Audited::Auditor do
|
|
206
381
|
it "should not save an audit if only specified on create/destroy" do
|
207
382
|
on_create_destroy = Models::ActiveRecord::OnCreateDestroy.create( name: 'Bart' )
|
208
383
|
expect {
|
209
|
-
on_create_destroy.
|
384
|
+
on_create_destroy.update! name: 'Changed'
|
210
385
|
}.to_not change( Audited::Audit, :count )
|
211
386
|
end
|
212
387
|
|
213
388
|
it "should not save an audit if the value doesn't change after type casting" do
|
214
|
-
@user.
|
389
|
+
@user.update! logins: 0, activated: true
|
215
390
|
expect { @user.update_attribute :logins, '0' }.to_not change( Audited::Audit, :count )
|
216
391
|
expect { @user.update_attribute :activated, 1 }.to_not change( Audited::Audit, :count )
|
217
392
|
expect { @user.update_attribute :activated, '1' }.to_not change( Audited::Audit, :count )
|
@@ -235,7 +410,7 @@ describe Audited::Auditor do
|
|
235
410
|
|
236
411
|
describe "on destroy" do
|
237
412
|
before do
|
238
|
-
@user = create_user
|
413
|
+
@user = create_user(status: :active)
|
239
414
|
end
|
240
415
|
|
241
416
|
it "should save an audit" do
|
@@ -260,6 +435,11 @@ describe Audited::Auditor do
|
|
260
435
|
expect(@user.audits.last.audited_changes).to eq(@user.audited_attributes)
|
261
436
|
end
|
262
437
|
|
438
|
+
it "should store enum value" do
|
439
|
+
@user.destroy
|
440
|
+
expect(@user.audits.last.audited_changes["status"]).to eq(0)
|
441
|
+
end
|
442
|
+
|
263
443
|
it "should be able to reconstruct a destroyed record without history" do
|
264
444
|
@user.audits.delete_all
|
265
445
|
@user.destroy
|
@@ -329,6 +509,77 @@ describe Audited::Auditor do
|
|
329
509
|
end
|
330
510
|
end
|
331
511
|
|
512
|
+
describe "max_audits" do
|
513
|
+
it "should respect global setting" do
|
514
|
+
stub_global_max_audits(10) do
|
515
|
+
expect(Models::ActiveRecord::User.audited_options[:max_audits]).to eq(10)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
it "should respect per model setting" do
|
520
|
+
stub_global_max_audits(10) do
|
521
|
+
expect(Models::ActiveRecord::MaxAuditsUser.audited_options[:max_audits]).to eq(5)
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
it "should delete old audits when keeped amount exceeded" do
|
526
|
+
stub_global_max_audits(2) do
|
527
|
+
user = create_versions(2)
|
528
|
+
user.update(name: 'John')
|
529
|
+
expect(user.audits.pluck(:version)).to eq([2, 3])
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
it "should not delete old audits when keeped amount not exceeded" do
|
534
|
+
stub_global_max_audits(3) do
|
535
|
+
user = create_versions(2)
|
536
|
+
user.update(name: 'John')
|
537
|
+
expect(user.audits.pluck(:version)).to eq([1, 2, 3])
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
it "should delete old extra audits after introducing limit" do
|
542
|
+
stub_global_max_audits(nil) do
|
543
|
+
user = Models::ActiveRecord::User.create!(name: 'Brandon', username: 'brandon')
|
544
|
+
user.update!(name: 'Foobar')
|
545
|
+
user.update!(name: 'Awesome', username: 'keepers')
|
546
|
+
user.update!(activated: true)
|
547
|
+
|
548
|
+
Audited.max_audits = 3
|
549
|
+
Models::ActiveRecord::User.send(:normalize_audited_options)
|
550
|
+
user.update!(favourite_device: 'Android Phone')
|
551
|
+
audits = user.audits
|
552
|
+
|
553
|
+
expect(audits.count).to eq(3)
|
554
|
+
expect(audits[0].audited_changes).to include({'name' => ['Foobar', 'Awesome'], 'username' => ['brandon', 'keepers']})
|
555
|
+
expect(audits[1].audited_changes).to eq({'activated' => [nil, true]})
|
556
|
+
expect(audits[2].audited_changes).to eq({'favourite_device' => [nil, 'Android Phone']})
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
it "should add comment line for combined audit" do
|
561
|
+
stub_global_max_audits(2) do
|
562
|
+
user = Models::ActiveRecord::User.create!(name: 'Foobar 1')
|
563
|
+
user.update(name: 'Foobar 2', audit_comment: 'First audit comment')
|
564
|
+
user.update(name: 'Foobar 3', audit_comment: 'Second audit comment')
|
565
|
+
expect(user.audits.first.comment).to match(/First audit comment.+is the result of multiple/m)
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
def stub_global_max_audits(max_audits)
|
570
|
+
previous_max_audits = Audited.max_audits
|
571
|
+
previous_user_audited_options = Models::ActiveRecord::User.audited_options.dup
|
572
|
+
begin
|
573
|
+
Audited.max_audits = max_audits
|
574
|
+
Models::ActiveRecord::User.send(:normalize_audited_options) # reloads audited_options
|
575
|
+
yield
|
576
|
+
ensure
|
577
|
+
Audited.max_audits = previous_max_audits
|
578
|
+
Models::ActiveRecord::User.audited_options = previous_user_audited_options
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
332
583
|
describe "revisions" do
|
333
584
|
let( :user ) { create_versions }
|
334
585
|
|
@@ -347,8 +598,8 @@ describe Audited::Auditor do
|
|
347
598
|
|
348
599
|
it "should set the attributes for each revision" do
|
349
600
|
u = Models::ActiveRecord::User.create(name: 'Brandon', username: 'brandon')
|
350
|
-
u.
|
351
|
-
u.
|
601
|
+
u.update! name: 'Foobar'
|
602
|
+
u.update! name: 'Awesome', username: 'keepers'
|
352
603
|
|
353
604
|
expect(u.revisions.size).to eql(3)
|
354
605
|
|
@@ -364,8 +615,8 @@ describe Audited::Auditor do
|
|
364
615
|
|
365
616
|
it "access to only recent revisions" do
|
366
617
|
u = Models::ActiveRecord::User.create(name: 'Brandon', username: 'brandon')
|
367
|
-
u.
|
368
|
-
u.
|
618
|
+
u.update! name: 'Foobar'
|
619
|
+
u.update! name: 'Awesome', username: 'keepers'
|
369
620
|
|
370
621
|
expect(u.revisions(2).size).to eq(2)
|
371
622
|
|
@@ -382,7 +633,7 @@ describe Audited::Auditor do
|
|
382
633
|
end
|
383
634
|
|
384
635
|
it "should ignore attributes that have been deleted" do
|
385
|
-
user.audits.last.
|
636
|
+
user.audits.last.update! audited_changes: {old_attribute: 'old value'}
|
386
637
|
expect { user.revisions }.to_not raise_error
|
387
638
|
end
|
388
639
|
end
|
@@ -397,21 +648,21 @@ describe Audited::Auditor do
|
|
397
648
|
it "should find the given revision" do
|
398
649
|
revision = user.revision(3)
|
399
650
|
expect(revision).to be_a_kind_of( Models::ActiveRecord::User )
|
400
|
-
expect(revision.
|
651
|
+
expect(revision.audit_version).to eq(3)
|
401
652
|
expect(revision.name).to eq('Foobar 3')
|
402
653
|
end
|
403
654
|
|
404
655
|
it "should find the previous revision with :previous" do
|
405
656
|
revision = user.revision(:previous)
|
406
|
-
expect(revision.
|
657
|
+
expect(revision.audit_version).to eq(4)
|
407
658
|
#expect(revision).to eq(user.revision(4))
|
408
659
|
expect(revision.attributes).to eq(user.revision(4).attributes)
|
409
660
|
end
|
410
661
|
|
411
662
|
it "should be able to get the previous revision repeatedly" do
|
412
663
|
previous = user.revision(:previous)
|
413
|
-
expect(previous.
|
414
|
-
expect(previous.revision(:previous).
|
664
|
+
expect(previous.audit_version).to eq(4)
|
665
|
+
expect(previous.revision(:previous).audit_version).to eq(3)
|
415
666
|
end
|
416
667
|
|
417
668
|
it "should be able to set protected attributes" do
|
@@ -431,8 +682,8 @@ describe Audited::Auditor do
|
|
431
682
|
|
432
683
|
it "should set the attributes for each revision" do
|
433
684
|
u = Models::ActiveRecord::User.create(name: 'Brandon', username: 'brandon')
|
434
|
-
u.
|
435
|
-
u.
|
685
|
+
u.update! name: 'Foobar'
|
686
|
+
u.update! name: 'Awesome', username: 'keepers'
|
436
687
|
|
437
688
|
expect(u.revision(3).name).to eq('Awesome')
|
438
689
|
expect(u.revision(3).username).to eq('keepers')
|
@@ -444,6 +695,16 @@ describe Audited::Auditor do
|
|
444
695
|
expect(u.revision(1).username).to eq('brandon')
|
445
696
|
end
|
446
697
|
|
698
|
+
it "should correctly restore revision with enum" do
|
699
|
+
u = Models::ActiveRecord::User.create(status: :active)
|
700
|
+
u.update_attribute(:status, :reliable)
|
701
|
+
u.update_attribute(:status, :banned)
|
702
|
+
|
703
|
+
expect(u.revision(3)).to be_banned
|
704
|
+
expect(u.revision(2)).to be_reliable
|
705
|
+
expect(u.revision(1)).to be_active
|
706
|
+
end
|
707
|
+
|
447
708
|
it "should be able to get time for first revision" do
|
448
709
|
suspended_at = Time.zone.now
|
449
710
|
u = Models::ActiveRecord::User.create(suspended_at: suspended_at)
|
@@ -484,8 +745,8 @@ describe Audited::Auditor do
|
|
484
745
|
audit = user.audits.first
|
485
746
|
audit.created_at = 1.hour.ago
|
486
747
|
audit.save!
|
487
|
-
user.
|
488
|
-
expect(user.revision_at( 2.minutes.ago ).
|
748
|
+
user.update! name: 'updated'
|
749
|
+
expect(user.revision_at( 2.minutes.ago ).audit_version).to eq(1)
|
489
750
|
end
|
490
751
|
|
491
752
|
it "should be nil if given a time before audits" do
|
@@ -493,6 +754,33 @@ describe Audited::Auditor do
|
|
493
754
|
end
|
494
755
|
end
|
495
756
|
|
757
|
+
describe "own_and_associated_audits" do
|
758
|
+
it "should return audits for self and associated audits" do
|
759
|
+
owner = Models::ActiveRecord::Owner.create!
|
760
|
+
company = owner.companies.create!
|
761
|
+
company.update!(name: "Collective Idea")
|
762
|
+
|
763
|
+
other_owner = Models::ActiveRecord::Owner.create!
|
764
|
+
other_owner.companies.create!
|
765
|
+
|
766
|
+
expect(owner.own_and_associated_audits).to match_array(owner.audits + company.audits)
|
767
|
+
end
|
768
|
+
|
769
|
+
it "should order audits by creation time" do
|
770
|
+
owner = Models::ActiveRecord::Owner.create!
|
771
|
+
first_audit = owner.audits.first
|
772
|
+
first_audit.update_column(:created_at, 1.year.ago)
|
773
|
+
|
774
|
+
company = owner.companies.create!
|
775
|
+
second_audit = company.audits.first
|
776
|
+
second_audit.update_column(:created_at, 1.month.ago)
|
777
|
+
|
778
|
+
company.update!(name: "Collective Idea")
|
779
|
+
third_audit = company.audits.last
|
780
|
+
expect(owner.own_and_associated_audits.to_a).to eq([third_audit, second_audit, first_audit])
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
496
784
|
describe "without auditing" do
|
497
785
|
it "should not save an audit when calling #save_without_auditing" do
|
498
786
|
expect {
|
@@ -513,72 +801,162 @@ describe Audited::Auditor do
|
|
513
801
|
end
|
514
802
|
|
515
803
|
it "should be thread safe using a #without_auditing block" do
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
804
|
+
skip if Models::ActiveRecord::User.connection.class.name.include?("SQLite")
|
805
|
+
|
806
|
+
t1 = Thread.new do
|
807
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
808
|
+
Models::ActiveRecord::User.without_auditing do
|
809
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
810
|
+
Models::ActiveRecord::User.create!( name: 'Bart' )
|
811
|
+
sleep 1
|
812
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
526
813
|
end
|
814
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
815
|
+
end
|
816
|
+
|
817
|
+
t2 = Thread.new do
|
818
|
+
sleep 0.5
|
819
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
820
|
+
Models::ActiveRecord::User.create!( name: 'Lisa' )
|
821
|
+
end
|
822
|
+
t1.join
|
823
|
+
t2.join
|
824
|
+
|
825
|
+
expect(Models::ActiveRecord::User.find_by_name('Bart').audits.count).to eq(0)
|
826
|
+
expect(Models::ActiveRecord::User.find_by_name('Lisa').audits.count).to eq(1)
|
827
|
+
end
|
828
|
+
|
829
|
+
it "should not save an audit when auditing is globally disabled" do
|
830
|
+
expect(Audited.auditing_enabled).to eq(true)
|
831
|
+
Audited.auditing_enabled = false
|
832
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
833
|
+
|
834
|
+
user = create_user
|
835
|
+
expect(user.audits.count).to eq(0)
|
836
|
+
|
837
|
+
Audited.auditing_enabled = true
|
838
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
839
|
+
|
840
|
+
user.update!(name: 'Test')
|
841
|
+
expect(user.audits.count).to eq(1)
|
842
|
+
Models::ActiveRecord::User.enable_auditing
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
describe "with auditing" do
|
847
|
+
it "should save an audit when calling #save_with_auditing" do
|
848
|
+
expect {
|
849
|
+
u = Models::ActiveRecord::User.new(name: 'Brandon')
|
850
|
+
Models::ActiveRecord::User.auditing_enabled = false
|
851
|
+
expect(u.save_with_auditing).to eq(true)
|
852
|
+
Models::ActiveRecord::User.auditing_enabled = true
|
853
|
+
}.to change( Audited::Audit, :count ).by(1)
|
854
|
+
end
|
855
|
+
|
856
|
+
it "should save an audit inside of the #with_auditing block" do
|
857
|
+
expect {
|
858
|
+
Models::ActiveRecord::User.auditing_enabled = false
|
859
|
+
Models::ActiveRecord::User.with_auditing { Models::ActiveRecord::User.create!( name: 'Brandon' ) }
|
860
|
+
Models::ActiveRecord::User.auditing_enabled = true
|
861
|
+
}.to change( Audited::Audit, :count ).by(1)
|
862
|
+
end
|
863
|
+
|
864
|
+
it "should reset auditing status even it raises an exception" do
|
865
|
+
Models::ActiveRecord::User.disable_auditing
|
866
|
+
Models::ActiveRecord::User.with_auditing { raise } rescue nil
|
867
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
868
|
+
Models::ActiveRecord::User.enable_auditing
|
869
|
+
end
|
870
|
+
|
871
|
+
it "should be thread safe using a #with_auditing block" do
|
872
|
+
skip if Models::ActiveRecord::User.connection.class.name.include?("SQLite")
|
527
873
|
|
528
|
-
|
529
|
-
|
874
|
+
t1 = Thread.new do
|
875
|
+
Models::ActiveRecord::User.disable_auditing
|
876
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
877
|
+
Models::ActiveRecord::User.with_auditing do
|
878
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
879
|
+
|
880
|
+
Models::ActiveRecord::User.create!( name: 'Shaggy' )
|
881
|
+
sleep 1
|
530
882
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
531
|
-
Models::ActiveRecord::User.create!( name: 'Lisa' )
|
532
883
|
end
|
533
|
-
|
534
|
-
|
884
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
885
|
+
Models::ActiveRecord::User.enable_auditing
|
886
|
+
end
|
535
887
|
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
888
|
+
t2 = Thread.new do
|
889
|
+
sleep 0.5
|
890
|
+
Models::ActiveRecord::User.disable_auditing
|
891
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
892
|
+
Models::ActiveRecord::User.create!( name: 'Scooby' )
|
893
|
+
Models::ActiveRecord::User.enable_auditing
|
540
894
|
end
|
895
|
+
t1.join
|
896
|
+
t2.join
|
897
|
+
|
898
|
+
Models::ActiveRecord::User.enable_auditing
|
899
|
+
expect(Models::ActiveRecord::User.find_by_name('Shaggy').audits.count).to eq(1)
|
900
|
+
expect(Models::ActiveRecord::User.find_by_name('Scooby').audits.count).to eq(0)
|
541
901
|
end
|
542
902
|
end
|
543
903
|
|
544
904
|
describe "comment required" do
|
545
905
|
|
546
906
|
describe "on create" do
|
547
|
-
it "should not validate when audit_comment is not supplied" do
|
548
|
-
expect(Models::ActiveRecord::CommentRequiredUser.new).not_to be_valid
|
907
|
+
it "should not validate when audit_comment is not supplied when initialized" do
|
908
|
+
expect(Models::ActiveRecord::CommentRequiredUser.new(name: 'Foo')).not_to be_valid
|
909
|
+
end
|
910
|
+
|
911
|
+
it "should not validate when audit_comment is not supplied trying to create" do
|
912
|
+
expect(Models::ActiveRecord::CommentRequiredUser.create(name: 'Foo')).not_to be_valid
|
549
913
|
end
|
550
914
|
|
551
915
|
it "should validate when audit_comment is supplied" do
|
552
|
-
expect(Models::ActiveRecord::CommentRequiredUser.
|
916
|
+
expect(Models::ActiveRecord::CommentRequiredUser.create(name: 'Foo', audit_comment: 'Create')).to be_valid
|
917
|
+
end
|
918
|
+
|
919
|
+
it "should validate when audit_comment is not supplied, and creating is not being audited" do
|
920
|
+
expect(Models::ActiveRecord::OnUpdateCommentRequiredUser.create(name: 'Foo')).to be_valid
|
921
|
+
expect(Models::ActiveRecord::OnDestroyCommentRequiredUser.create(name: 'Foo')).to be_valid
|
553
922
|
end
|
554
923
|
|
555
924
|
it "should validate when audit_comment is not supplied, and auditing is disabled" do
|
556
925
|
Models::ActiveRecord::CommentRequiredUser.disable_auditing
|
557
|
-
expect(Models::ActiveRecord::CommentRequiredUser.
|
926
|
+
expect(Models::ActiveRecord::CommentRequiredUser.create(name: 'Foo')).to be_valid
|
558
927
|
Models::ActiveRecord::CommentRequiredUser.enable_auditing
|
559
928
|
end
|
560
929
|
end
|
561
930
|
|
562
931
|
describe "on update" do
|
563
932
|
let( :user ) { Models::ActiveRecord::CommentRequiredUser.create!( audit_comment: 'Create' ) }
|
933
|
+
let( :on_create_user ) { Models::ActiveRecord::OnDestroyCommentRequiredUser.create }
|
934
|
+
let( :on_destroy_user ) { Models::ActiveRecord::OnDestroyCommentRequiredUser.create }
|
564
935
|
|
565
936
|
it "should not validate when audit_comment is not supplied" do
|
566
|
-
expect(user.
|
937
|
+
expect(user.update(name: 'Test')).to eq(false)
|
938
|
+
end
|
939
|
+
|
940
|
+
it "should validate when audit_comment is not supplied, and updating is not being audited" do
|
941
|
+
expect(on_create_user.update(name: 'Test')).to eq(true)
|
942
|
+
expect(on_destroy_user.update(name: 'Test')).to eq(true)
|
567
943
|
end
|
568
944
|
|
569
945
|
it "should validate when audit_comment is supplied" do
|
570
|
-
expect(user.
|
946
|
+
expect(user.update(name: 'Test', audit_comment: 'Update')).to eq(true)
|
571
947
|
end
|
572
948
|
|
573
949
|
it "should validate when audit_comment is not supplied, and auditing is disabled" do
|
574
950
|
Models::ActiveRecord::CommentRequiredUser.disable_auditing
|
575
|
-
expect(user.
|
951
|
+
expect(user.update(name: 'Test')).to eq(true)
|
576
952
|
Models::ActiveRecord::CommentRequiredUser.enable_auditing
|
577
953
|
end
|
578
954
|
end
|
579
955
|
|
580
956
|
describe "on destroy" do
|
581
957
|
let( :user ) { Models::ActiveRecord::CommentRequiredUser.create!( audit_comment: 'Create' )}
|
958
|
+
let( :on_create_user ) { Models::ActiveRecord::OnCreateCommentRequiredUser.create!( audit_comment: 'Create' ) }
|
959
|
+
let( :on_update_user ) { Models::ActiveRecord::OnUpdateCommentRequiredUser.create }
|
582
960
|
|
583
961
|
it "should not validate when audit_comment is not supplied" do
|
584
962
|
expect(user.destroy).to eq(false)
|
@@ -589,6 +967,11 @@ describe Audited::Auditor do
|
|
589
967
|
expect(user.destroy).to eq(user)
|
590
968
|
end
|
591
969
|
|
970
|
+
it "should validate when audit_comment is not supplied, and destroying is not being audited" do
|
971
|
+
expect(on_create_user.destroy).to eq(on_create_user)
|
972
|
+
expect(on_update_user.destroy).to eq(on_update_user)
|
973
|
+
end
|
974
|
+
|
592
975
|
it "should validate when audit_comment is not supplied, and auditing is disabled" do
|
593
976
|
Models::ActiveRecord::CommentRequiredUser.disable_auditing
|
594
977
|
expect(user.destroy).to eq(user)
|
@@ -598,6 +981,16 @@ describe Audited::Auditor do
|
|
598
981
|
|
599
982
|
end
|
600
983
|
|
984
|
+
describe "no update with comment only" do
|
985
|
+
let( :user ) { Models::ActiveRecord::NoUpdateWithCommentOnlyUser.create }
|
986
|
+
|
987
|
+
it "does not create an audit when only an audit_comment is present" do
|
988
|
+
user.audit_comment = "Comment"
|
989
|
+
expect { user.save! }.to_not change( Audited::Audit, :count )
|
990
|
+
end
|
991
|
+
|
992
|
+
end
|
993
|
+
|
601
994
|
describe "attr_protected and attr_accessible" do
|
602
995
|
|
603
996
|
it "should not raise error when attr_accessible is set and protected is false" do
|
@@ -619,7 +1012,7 @@ describe Audited::Auditor do
|
|
619
1012
|
it "should record user objects" do
|
620
1013
|
Models::ActiveRecord::Company.audit_as( user ) do
|
621
1014
|
company = Models::ActiveRecord::Company.create name: 'The auditors'
|
622
|
-
company.
|
1015
|
+
company.update! name: 'The Auditors'
|
623
1016
|
|
624
1017
|
company.audits.each do |audit|
|
625
1018
|
expect(audit.user).to eq(user)
|
@@ -630,7 +1023,7 @@ describe Audited::Auditor do
|
|
630
1023
|
it "should record usernames" do
|
631
1024
|
Models::ActiveRecord::Company.audit_as( user.name ) do
|
632
1025
|
company = Models::ActiveRecord::Company.create name: 'The auditors'
|
633
|
-
company.
|
1026
|
+
company.update! name: 'The Auditors'
|
634
1027
|
|
635
1028
|
company.audits.each do |audit|
|
636
1029
|
expect(audit.user).to eq(user.name)
|
@@ -640,7 +1033,7 @@ describe Audited::Auditor do
|
|
640
1033
|
end
|
641
1034
|
|
642
1035
|
describe "after_audit" do
|
643
|
-
let( :user ) {
|
1036
|
+
let( :user ) { Models::ActiveRecord::UserWithAfterAudit.new }
|
644
1037
|
|
645
1038
|
it "should invoke after_audit callback on create" do
|
646
1039
|
expect(user.bogus_attr).to be_nil
|
@@ -650,7 +1043,7 @@ describe Audited::Auditor do
|
|
650
1043
|
end
|
651
1044
|
|
652
1045
|
describe "around_audit" do
|
653
|
-
let( :user ) {
|
1046
|
+
let( :user ) { Models::ActiveRecord::UserWithAfterAudit.new }
|
654
1047
|
|
655
1048
|
it "should invoke around_audit callback on create" do
|
656
1049
|
expect(user.around_attr).to be_nil
|
@@ -665,7 +1058,7 @@ describe Audited::Auditor do
|
|
665
1058
|
expect(company.type).to eq("Models::ActiveRecord::Company::STICompany")
|
666
1059
|
expect {
|
667
1060
|
Models::ActiveRecord::Company.auditing_enabled = false
|
668
|
-
company.
|
1061
|
+
company.update! name: 'STI auditors'
|
669
1062
|
Models::ActiveRecord::Company.auditing_enabled = true
|
670
1063
|
}.to_not change( Audited::Audit, :count )
|
671
1064
|
end
|