audited 4.9.0 → 5.4.3
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 +4 -4
- data/.github/workflows/buildlight.yml +15 -0
- data/.github/workflows/ci.yml +145 -0
- data/.github/workflows/publish_gem.yml +28 -0
- data/.standard.yml +5 -0
- data/Appraisals +35 -16
- data/CHANGELOG.md +162 -1
- data/Gemfile +1 -1
- data/README.md +73 -18
- data/Rakefile +5 -7
- data/gemfiles/rails50.gemfile +2 -0
- data/gemfiles/rails51.gemfile +2 -0
- data/gemfiles/rails52.gemfile +3 -1
- data/gemfiles/rails60.gemfile +1 -1
- data/gemfiles/rails61.gemfile +10 -0
- data/gemfiles/rails70.gemfile +10 -0
- data/gemfiles/rails71.gemfile +10 -0
- data/lib/audited/audit.rb +41 -29
- data/lib/audited/auditor.rb +134 -56
- data/lib/audited/railtie.rb +16 -0
- data/lib/audited/rspec_matchers.rb +5 -3
- data/lib/audited/sweeper.rb +3 -10
- data/lib/audited/version.rb +3 -1
- data/lib/audited-rspec.rb +3 -1
- data/lib/audited.rb +31 -9
- data/lib/generators/audited/install_generator.rb +9 -7
- data/lib/generators/audited/migration.rb +12 -2
- data/lib/generators/audited/migration_helper.rb +3 -1
- data/lib/generators/audited/templates/add_association_to_audits.rb +2 -0
- data/lib/generators/audited/templates/add_comment_to_audits.rb +2 -0
- data/lib/generators/audited/templates/add_remote_address_to_audits.rb +2 -0
- data/lib/generators/audited/templates/add_request_uuid_to_audits.rb +2 -0
- data/lib/generators/audited/templates/add_version_to_auditable_index.rb +2 -0
- data/lib/generators/audited/templates/install.rb +2 -0
- data/lib/generators/audited/templates/rename_association_to_associated.rb +2 -0
- data/lib/generators/audited/templates/rename_changes_to_audited_changes.rb +2 -0
- data/lib/generators/audited/templates/rename_parent_to_association.rb +2 -0
- data/lib/generators/audited/templates/revert_polymorphic_indexes_order.rb +2 -0
- data/lib/generators/audited/upgrade_generator.rb +16 -14
- data/spec/audited/audit_spec.rb +70 -48
- data/spec/audited/auditor_spec.rb +477 -246
- data/spec/audited/sweeper_spec.rb +19 -18
- data/spec/audited_spec.rb +14 -0
- data/spec/audited_spec_helpers.rb +11 -7
- data/spec/rails_app/app/assets/config/manifest.js +2 -0
- data/spec/rails_app/config/application.rb +32 -3
- data/spec/rails_app/config/database.yml +3 -2
- data/spec/rails_app/config/environment.rb +1 -1
- data/spec/rails_app/config/environments/test.rb +10 -5
- data/spec/rails_app/config/initializers/secret_token.rb +2 -2
- data/spec/spec_helper.rb +14 -14
- data/spec/support/active_record/models.rb +62 -13
- data/spec/support/active_record/postgres/1_change_audited_changes_type_to_json.rb +1 -2
- data/spec/support/active_record/postgres/2_change_audited_changes_type_to_jsonb.rb +1 -2
- data/spec/support/active_record/schema.rb +26 -19
- data/test/db/version_1.rb +2 -2
- data/test/db/version_2.rb +2 -2
- data/test/db/version_3.rb +2 -3
- data/test/db/version_4.rb +2 -3
- data/test/db/version_5.rb +0 -1
- data/test/db/version_6.rb +1 -1
- data/test/install_generator_test.rb +18 -19
- data/test/test_helper.rb +5 -5
- data/test/upgrade_generator_test.rb +13 -18
- metadata +49 -31
- data/.rubocop.yml +0 -25
- data/.travis.yml +0 -58
- data/gemfiles/rails42.gemfile +0 -11
- data/spec/rails_app/app/controllers/application_controller.rb +0 -2
- data/spec/rails_app/config/environments/development.rb +0 -21
- data/spec/rails_app/config/environments/production.rb +0 -35
@@ -1,19 +1,82 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
|
3
|
+
# not testing proxy_respond_to? hack / 2 methods / deprecation of `version`
|
4
|
+
# also, an additional 6 around `after_touch` for Versions before 6.
|
5
|
+
uncovered = (ActiveRecord::VERSION::MAJOR < 6) ? 15 : 9
|
6
|
+
SingleCov.covered! uncovered: uncovered
|
4
7
|
|
5
|
-
|
8
|
+
class ConditionalPrivateCompany < ::ActiveRecord::Base
|
9
|
+
self.table_name = "companies"
|
10
|
+
|
11
|
+
audited if: :foo?
|
12
|
+
|
13
|
+
private def foo?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ConditionalCompany < ::ActiveRecord::Base
|
19
|
+
self.table_name = "companies"
|
20
|
+
|
21
|
+
audited if: :public?
|
22
|
+
|
23
|
+
def public?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class ExclusiveCompany < ::ActiveRecord::Base
|
28
|
+
self.table_name = "companies"
|
29
|
+
audited if: proc { false }
|
30
|
+
end
|
31
|
+
|
32
|
+
class ExclusionaryCompany < ::ActiveRecord::Base
|
33
|
+
self.table_name = "companies"
|
34
|
+
|
35
|
+
audited unless: :non_profit?
|
36
|
+
|
37
|
+
def non_profit?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class ExclusionaryCompany2 < ::ActiveRecord::Base
|
42
|
+
self.table_name = "companies"
|
43
|
+
audited unless: proc { |c| c.exclusive? }
|
44
|
+
|
45
|
+
def exclusive?
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
6
49
|
|
50
|
+
class InclusiveCompany < ::ActiveRecord::Base
|
51
|
+
self.table_name = "companies"
|
52
|
+
audited if: proc { true }
|
53
|
+
end
|
54
|
+
|
55
|
+
class InclusiveCompany2 < ::ActiveRecord::Base
|
56
|
+
self.table_name = "companies"
|
57
|
+
audited unless: proc { false }
|
58
|
+
end
|
59
|
+
|
60
|
+
class Secret < ::ActiveRecord::Base
|
61
|
+
audited
|
62
|
+
end
|
63
|
+
|
64
|
+
class Secret2 < ::ActiveRecord::Base
|
65
|
+
audited
|
66
|
+
self.non_audited_columns = ["delta", "top_secret", "created_at"]
|
67
|
+
end
|
68
|
+
|
69
|
+
describe Audited::Auditor do
|
7
70
|
describe "configuration" do
|
8
71
|
it "should include instance methods" do
|
9
|
-
expect(Models::ActiveRecord::User.new).to be_a_kind_of(
|
72
|
+
expect(Models::ActiveRecord::User.new).to be_a_kind_of(Audited::Auditor::AuditedInstanceMethods)
|
10
73
|
end
|
11
74
|
|
12
75
|
it "should include class methods" do
|
13
|
-
expect(Models::ActiveRecord::User).to be_a_kind_of(
|
76
|
+
expect(Models::ActiveRecord::User).to be_a_kind_of(Audited::Auditor::AuditedClassMethods)
|
14
77
|
end
|
15
78
|
|
16
|
-
[
|
79
|
+
["created_at", "updated_at", "created_on", "updated_on", "lock_version", "id", "password"].each do |column|
|
17
80
|
it "should not audit #{column}" do
|
18
81
|
expect(Models::ActiveRecord::User.non_audited_columns).to include(column)
|
19
82
|
end
|
@@ -25,64 +88,29 @@ describe Audited::Auditor do
|
|
25
88
|
context "when condition method is private" do
|
26
89
|
subject { ConditionalPrivateCompany.new.send(:auditing_enabled) }
|
27
90
|
|
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
91
|
it { is_expected.to be_truthy }
|
41
92
|
end
|
42
93
|
|
43
94
|
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
95
|
context "when conditions are true" do
|
55
96
|
before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(true) }
|
56
|
-
it
|
97
|
+
it { is_expected.to be_truthy }
|
57
98
|
end
|
58
99
|
|
59
100
|
context "when conditions are false" do
|
60
101
|
before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(false) }
|
61
|
-
it
|
102
|
+
it { is_expected.to be_falsey }
|
62
103
|
end
|
63
104
|
end
|
64
105
|
|
65
106
|
context "when passing a Proc" do
|
66
107
|
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
108
|
subject { InclusiveCompany.new.send(:auditing_enabled) }
|
75
109
|
|
76
110
|
it { is_expected.to be_truthy }
|
77
111
|
end
|
78
112
|
|
79
113
|
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
114
|
subject { ExclusiveCompany.new.send(:auditing_enabled) }
|
87
115
|
it { is_expected.to be_falsey }
|
88
116
|
end
|
@@ -91,76 +119,40 @@ describe Audited::Auditor do
|
|
91
119
|
|
92
120
|
context "should be configurable which conditions aren't audited" do
|
93
121
|
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
122
|
subject { ExclusionaryCompany.new.send(:auditing_enabled) }
|
105
123
|
|
106
124
|
context "when conditions are true" do
|
107
125
|
before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(true) }
|
108
|
-
it
|
126
|
+
it { is_expected.to be_falsey }
|
109
127
|
end
|
110
128
|
|
111
129
|
context "when conditions are false" do
|
112
130
|
before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(false) }
|
113
|
-
it
|
131
|
+
it { is_expected.to be_truthy }
|
114
132
|
end
|
115
133
|
end
|
116
134
|
|
117
135
|
context "when using a proc" do
|
118
136
|
context "when conditions are true" do
|
119
|
-
|
120
|
-
|
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 }
|
137
|
+
subject { ExclusionaryCompany2.new.send(:auditing_enabled) }
|
138
|
+
it { is_expected.to be_falsey }
|
132
139
|
end
|
133
140
|
|
134
141
|
context "when conditions are false" do
|
135
|
-
|
136
|
-
|
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 }
|
142
|
+
subject { InclusiveCompany2.new.send(:auditing_enabled) }
|
143
|
+
it { is_expected.to be_truthy }
|
144
144
|
end
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
148
148
|
it "should be configurable which attributes are not audited via ignored_attributes" do
|
149
|
-
Audited.ignored_attributes = [
|
150
|
-
class Secret < ::ActiveRecord::Base
|
151
|
-
audited
|
152
|
-
end
|
149
|
+
Audited.ignored_attributes = ["delta", "top_secret", "created_at", "updated_at"]
|
153
150
|
|
154
|
-
expect(Secret.non_audited_columns).to include(
|
151
|
+
expect(Secret.non_audited_columns).to include("delta", "top_secret", "created_at")
|
155
152
|
end
|
156
153
|
|
157
154
|
it "should be configurable which attributes are not audited via non_audited_columns=" do
|
158
|
-
|
159
|
-
audited
|
160
|
-
self.non_audited_columns = ['delta', 'top_secret', 'created_at']
|
161
|
-
end
|
162
|
-
|
163
|
-
expect(Secret2.non_audited_columns).to include('delta', 'top_secret', 'created_at')
|
155
|
+
expect(Secret2.non_audited_columns).to include("delta", "top_secret", "created_at")
|
164
156
|
end
|
165
157
|
|
166
158
|
it "should not save non-audited columns" do
|
@@ -168,7 +160,7 @@ describe Audited::Auditor do
|
|
168
160
|
begin
|
169
161
|
Models::ActiveRecord::User.non_audited_columns += [:favourite_device]
|
170
162
|
|
171
|
-
expect(create_user.audits.first.audited_changes.keys.any? { |col| [
|
163
|
+
expect(create_user.audits.first.audited_changes.keys.any? { |col| ["favourite_device", "created_at", "updated_at", "password"].include?(col) }).to eq(false)
|
172
164
|
ensure
|
173
165
|
Models::ActiveRecord::User.non_audited_columns = previous
|
174
166
|
end
|
@@ -190,7 +182,7 @@ describe Audited::Auditor do
|
|
190
182
|
user.password = "password"
|
191
183
|
user.non_column_attr = "some value"
|
192
184
|
user.save!
|
193
|
-
expect(user.audits.last.audited_changes.keys).to eq(%w
|
185
|
+
expect(user.audits.last.audited_changes.keys).to eq(%w[password])
|
194
186
|
end
|
195
187
|
|
196
188
|
it "should save attributes not specified in 'except' option" do
|
@@ -209,10 +201,80 @@ describe Audited::Auditor do
|
|
209
201
|
user.password = "password"
|
210
202
|
user.non_column_attr = "some value"
|
211
203
|
user.save!
|
212
|
-
expect(user.audits.last.audited_changes.keys).to eq(%w
|
204
|
+
expect(user.audits.last.audited_changes.keys).to eq(%w[non_column_attr])
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should redact columns specified in 'redacted' option" do
|
208
|
+
redacted = Audited::Auditor::AuditedInstanceMethods::REDACTED
|
209
|
+
user = Models::ActiveRecord::UserRedactedPassword.create(password: "password")
|
210
|
+
user.save!
|
211
|
+
expect(user.audits.last.audited_changes["password"]).to eq(redacted)
|
212
|
+
user.password = "new_password"
|
213
|
+
user.save!
|
214
|
+
expect(user.audits.last.audited_changes["password"]).to eq([redacted, redacted])
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should redact columns specified in 'redacted' option when there are multiple specified" do
|
218
|
+
redacted = Audited::Auditor::AuditedInstanceMethods::REDACTED
|
219
|
+
user =
|
220
|
+
Models::ActiveRecord::UserMultipleRedactedAttributes.create(
|
221
|
+
password: "password"
|
222
|
+
)
|
223
|
+
user.save!
|
224
|
+
expect(user.audits.last.audited_changes["password"]).to eq(redacted)
|
225
|
+
# Saving '[REDACTED]' value for 'ssn' even if value wasn't set explicitly when record was created
|
226
|
+
expect(user.audits.last.audited_changes["ssn"]).to eq(redacted)
|
227
|
+
|
228
|
+
user.password = "new_password"
|
229
|
+
user.ssn = 987654321
|
230
|
+
user.save!
|
231
|
+
expect(user.audits.last.audited_changes["password"]).to eq([redacted, redacted])
|
232
|
+
expect(user.audits.last.audited_changes["ssn"]).to eq([redacted, redacted])
|
233
|
+
|
234
|
+
# If we haven't changed any attrs from 'redacted' list, audit should not contain these keys
|
235
|
+
user.name = "new name"
|
236
|
+
user.save!
|
237
|
+
expect(user.audits.last.audited_changes).to have_key("name")
|
238
|
+
expect(user.audits.last.audited_changes).not_to have_key("password")
|
239
|
+
expect(user.audits.last.audited_changes).not_to have_key("ssn")
|
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
|
+
context "when ignored_default_callbacks is set" do
|
249
|
+
before { Audited.ignored_default_callbacks = [:create] }
|
250
|
+
after { Audited.ignored_default_callbacks = [] }
|
251
|
+
|
252
|
+
it "should remove create callback" do
|
253
|
+
class DefaultCallback < ::ActiveRecord::Base
|
254
|
+
audited
|
255
|
+
end
|
256
|
+
|
257
|
+
expect(DefaultCallback.audited_options[:on]).to eq([:update, :touch, :destroy])
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should keep create callback if specified" do
|
261
|
+
class CallbacksSpecified < ::ActiveRecord::Base
|
262
|
+
audited on: [:create, :update, :destroy]
|
263
|
+
end
|
264
|
+
|
265
|
+
expect(CallbacksSpecified.audited_options[:on]).to eq([:create, :update, :destroy])
|
266
|
+
end
|
213
267
|
end
|
214
268
|
|
215
|
-
if ActiveRecord::
|
269
|
+
if ::ActiveRecord::VERSION::MAJOR >= 7
|
270
|
+
it "should filter encrypted attributes" do
|
271
|
+
user = Models::ActiveRecord::UserWithEncryptedPassword.create(password: "password")
|
272
|
+
user.save
|
273
|
+
expect(user.audits.last.audited_changes["password"]).to eq("[FILTERED]")
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
216
278
|
describe "'json' and 'jsonb' audited_changes column type" do
|
217
279
|
let(:migrations_path) { SPEC_ROOT.join("support/active_record/postgres") }
|
218
280
|
|
@@ -249,16 +311,16 @@ describe Audited::Auditor do
|
|
249
311
|
it "should allow mass assignment of all unprotected attributes" do
|
250
312
|
yesterday = 1.day.ago
|
251
313
|
|
252
|
-
u = Models::ActiveRecord::NoAttributeProtectionUser.new(name:
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
314
|
+
u = Models::ActiveRecord::NoAttributeProtectionUser.new(name: "name",
|
315
|
+
username: "username",
|
316
|
+
password: "password",
|
317
|
+
activated: true,
|
318
|
+
suspended_at: yesterday,
|
319
|
+
logins: 2)
|
258
320
|
|
259
|
-
expect(u.name).to eq(
|
260
|
-
expect(u.username).to eq(
|
261
|
-
expect(u.password).to eq(
|
321
|
+
expect(u.name).to eq("name")
|
322
|
+
expect(u.username).to eq("username")
|
323
|
+
expect(u.password).to eq("password")
|
262
324
|
expect(u.activated).to eq(true)
|
263
325
|
expect(u.suspended_at.to_i).to eq(yesterday.to_i)
|
264
326
|
expect(u.logins).to eq(2)
|
@@ -266,12 +328,12 @@ describe Audited::Auditor do
|
|
266
328
|
end
|
267
329
|
|
268
330
|
describe "on create" do
|
269
|
-
let(
|
331
|
+
let(:user) { create_user status: :reliable, audit_comment: "Create" }
|
270
332
|
|
271
333
|
it "should change the audit count" do
|
272
334
|
expect {
|
273
335
|
user
|
274
|
-
}.to change(
|
336
|
+
}.to change(Audited::Audit, :count).by(1)
|
275
337
|
end
|
276
338
|
|
277
339
|
it "should create associated audit" do
|
@@ -279,7 +341,7 @@ describe Audited::Auditor do
|
|
279
341
|
end
|
280
342
|
|
281
343
|
it "should set the action to create" do
|
282
|
-
expect(user.audits.first.action).to eq(
|
344
|
+
expect(user.audits.first.action).to eq("create")
|
283
345
|
expect(Audited::Audit.creates.order(:id).last).to eq(user.audits.first)
|
284
346
|
expect(user.audits.creates.count).to eq(1)
|
285
347
|
expect(user.audits.updates.count).to eq(0)
|
@@ -294,46 +356,61 @@ describe Audited::Auditor do
|
|
294
356
|
expect(user.audits.first.audited_changes["status"]).to eq(1)
|
295
357
|
end
|
296
358
|
|
359
|
+
context "when store_synthesized_enums is set to true" do
|
360
|
+
before { Audited.store_synthesized_enums = true }
|
361
|
+
after { Audited.store_synthesized_enums = false }
|
362
|
+
|
363
|
+
it "should store enum value as Rails synthesized value" do
|
364
|
+
expect(user.audits.first.audited_changes["status"]).to eq("reliable")
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
297
368
|
it "should store comment" do
|
298
|
-
expect(user.audits.first.comment).to eq(
|
369
|
+
expect(user.audits.first.comment).to eq("Create")
|
299
370
|
end
|
300
371
|
|
301
372
|
it "should not audit an attribute which is excepted if specified on create or destroy" do
|
302
|
-
on_create_destroy_except_name = Models::ActiveRecord::OnCreateDestroyExceptName.create(name:
|
303
|
-
expect(on_create_destroy_except_name.audits.first.audited_changes.keys.any?{|col| [
|
373
|
+
on_create_destroy_except_name = Models::ActiveRecord::OnCreateDestroyExceptName.create(name: "Bart")
|
374
|
+
expect(on_create_destroy_except_name.audits.first.audited_changes.keys.any? { |col| ["name"].include? col }).to eq(false)
|
304
375
|
end
|
305
376
|
|
306
377
|
it "should not save an audit if only specified on update/destroy" do
|
307
378
|
expect {
|
308
|
-
Models::ActiveRecord::OnUpdateDestroy.create!(
|
309
|
-
}.to_not change(
|
379
|
+
Models::ActiveRecord::OnUpdateDestroy.create!(name: "Bart")
|
380
|
+
}.to_not change(Audited::Audit, :count)
|
381
|
+
end
|
382
|
+
|
383
|
+
it "should save readonly columns" do
|
384
|
+
expect {
|
385
|
+
Models::ActiveRecord::UserWithReadOnlyAttrs.create!(name: "Bart")
|
386
|
+
}.to change(Audited::Audit, :count)
|
310
387
|
end
|
311
388
|
end
|
312
389
|
|
313
390
|
describe "on update" do
|
314
391
|
before do
|
315
|
-
@user = create_user(
|
392
|
+
@user = create_user(name: "Brandon", status: :active, audit_comment: "Update")
|
316
393
|
end
|
317
394
|
|
318
395
|
it "should save an audit" do
|
319
396
|
expect {
|
320
397
|
@user.update_attribute(:name, "Someone")
|
321
|
-
}.to change(
|
398
|
+
}.to change(Audited::Audit, :count).by(1)
|
322
399
|
expect {
|
323
400
|
@user.update_attribute(:name, "Someone else")
|
324
|
-
}.to change(
|
401
|
+
}.to change(Audited::Audit, :count).by(1)
|
325
402
|
end
|
326
403
|
|
327
404
|
it "should set the action to 'update'" do
|
328
|
-
@user.update! name:
|
329
|
-
expect(@user.audits.last.action).to eq(
|
405
|
+
@user.update! name: "Changed"
|
406
|
+
expect(@user.audits.last.action).to eq("update")
|
330
407
|
expect(Audited::Audit.updates.order(:id).last).to eq(@user.audits.last)
|
331
408
|
expect(@user.audits.updates.last).to eq(@user.audits.last)
|
332
409
|
end
|
333
410
|
|
334
411
|
it "should store the changed attributes" do
|
335
|
-
@user.update! name:
|
336
|
-
expect(@user.audits.last.audited_changes).to eq({
|
412
|
+
@user.update! name: "Changed"
|
413
|
+
expect(@user.audits.last.audited_changes).to eq({"name" => ["Brandon", "Changed"]})
|
337
414
|
end
|
338
415
|
|
339
416
|
it "should store changed enum values" do
|
@@ -342,35 +419,138 @@ describe Audited::Auditor do
|
|
342
419
|
end
|
343
420
|
|
344
421
|
it "should store audit comment" do
|
345
|
-
expect(@user.audits.last.comment).to eq(
|
422
|
+
expect(@user.audits.last.comment).to eq("Update")
|
346
423
|
end
|
347
424
|
|
348
425
|
it "should not save an audit if only specified on create/destroy" do
|
349
|
-
on_create_destroy = Models::ActiveRecord::OnCreateDestroy.create(
|
426
|
+
on_create_destroy = Models::ActiveRecord::OnCreateDestroy.create(name: "Bart")
|
350
427
|
expect {
|
351
|
-
on_create_destroy.update! name:
|
352
|
-
}.to_not change(
|
428
|
+
on_create_destroy.update! name: "Changed"
|
429
|
+
}.to_not change(Audited::Audit, :count)
|
353
430
|
end
|
354
431
|
|
355
432
|
it "should not save an audit if the value doesn't change after type casting" do
|
356
433
|
@user.update! logins: 0, activated: true
|
357
|
-
expect { @user.update_attribute :logins,
|
358
|
-
expect { @user.update_attribute :activated, 1 }.to_not change(
|
359
|
-
expect { @user.update_attribute :activated,
|
434
|
+
expect { @user.update_attribute :logins, "0" }.to_not change(Audited::Audit, :count)
|
435
|
+
expect { @user.update_attribute :activated, 1 }.to_not change(Audited::Audit, :count)
|
436
|
+
expect { @user.update_attribute :activated, "1" }.to_not change(Audited::Audit, :count)
|
437
|
+
end
|
438
|
+
|
439
|
+
context "with readonly attributes" do
|
440
|
+
before do
|
441
|
+
@user = create_user_with_readonly_attrs(status: "active")
|
442
|
+
end
|
443
|
+
|
444
|
+
it "should not save readonly columns" do
|
445
|
+
expect { @user.update! status: "banned" }.to_not change(Audited::Audit, :count)
|
446
|
+
end
|
360
447
|
end
|
361
448
|
|
362
449
|
describe "with no dirty changes" do
|
363
450
|
it "does not create an audit if the record is not changed" do
|
364
451
|
expect {
|
365
452
|
@user.save!
|
366
|
-
}.to_not change(
|
453
|
+
}.to_not change(Audited::Audit, :count)
|
367
454
|
end
|
368
455
|
|
369
456
|
it "creates an audit when an audit comment is present" do
|
370
457
|
expect {
|
371
458
|
@user.audit_comment = "Comment"
|
372
459
|
@user.save!
|
373
|
-
}.to change(
|
460
|
+
}.to change(Audited::Audit, :count)
|
461
|
+
end
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
if ::ActiveRecord::VERSION::MAJOR >= 6
|
466
|
+
describe "on touch" do
|
467
|
+
before do
|
468
|
+
@user = create_user(name: "Brandon", status: :active)
|
469
|
+
end
|
470
|
+
|
471
|
+
it "should save an audit" do
|
472
|
+
expect { @user.touch(:suspended_at) }.to change(Audited::Audit, :count).by(1)
|
473
|
+
end
|
474
|
+
|
475
|
+
it "should set the action to 'update'" do
|
476
|
+
@user.touch(:suspended_at)
|
477
|
+
expect(@user.audits.last.action).to eq("update")
|
478
|
+
expect(Audited::Audit.updates.order(:id).last).to eq(@user.audits.last)
|
479
|
+
expect(@user.audits.updates.last).to eq(@user.audits.last)
|
480
|
+
end
|
481
|
+
|
482
|
+
it "should store the changed attributes" do
|
483
|
+
@user.touch(:suspended_at)
|
484
|
+
expect(@user.audits.last.audited_changes["suspended_at"][0]).to be_nil
|
485
|
+
expect(Time.parse(@user.audits.last.audited_changes["suspended_at"][1].to_s)).to be_within(2.seconds).of(Time.current)
|
486
|
+
end
|
487
|
+
|
488
|
+
it "should store audit comment" do
|
489
|
+
@user.audit_comment = "Here exists a touch comment"
|
490
|
+
@user.touch(:suspended_at)
|
491
|
+
expect(@user.audits.last.action).to eq("update")
|
492
|
+
expect(@user.audits.last.comment).to eq("Here exists a touch comment")
|
493
|
+
end
|
494
|
+
|
495
|
+
it "should not save an audit if only specified on create/destroy" do
|
496
|
+
on_create_destroy = Models::ActiveRecord::OnCreateDestroyUser.create(name: "Bart")
|
497
|
+
expect {
|
498
|
+
on_create_destroy.touch(:suspended_at)
|
499
|
+
}.to_not change(Audited::Audit, :count)
|
500
|
+
end
|
501
|
+
|
502
|
+
it "should store an audit if touch is the only audit" do
|
503
|
+
on_touch = Models::ActiveRecord::OnTouchOnly.create(name: "Bart")
|
504
|
+
expect {
|
505
|
+
on_touch.update(name: "NotBart")
|
506
|
+
}.to_not change(Audited::Audit, :count)
|
507
|
+
expect {
|
508
|
+
on_touch.touch(:suspended_at)
|
509
|
+
}.to change(on_touch.audits, :count).from(0).to(1)
|
510
|
+
|
511
|
+
@user.audits.destroy_all
|
512
|
+
expect(@user.audits).to be_empty
|
513
|
+
expect {
|
514
|
+
@user.touch(:suspended_at)
|
515
|
+
}.to change(@user.audits, :count).from(0).to(1)
|
516
|
+
end
|
517
|
+
|
518
|
+
context "don't double audit" do
|
519
|
+
let(:user) { Models::ActiveRecord::Owner.create(name: "OwnerUser", suspended_at: 1.month.ago, companies_attributes: [{name: "OwnedCompany"}]) }
|
520
|
+
let(:company) { user.companies.first }
|
521
|
+
|
522
|
+
it "should only create 1 (create) audit for object" do
|
523
|
+
expect(user.audits.count).to eq(1)
|
524
|
+
expect(user.audits.first.action).to eq("create")
|
525
|
+
end
|
526
|
+
|
527
|
+
it "should only create 1 (create) audit for nested resource" do
|
528
|
+
expect(company.audits.count).to eq(1)
|
529
|
+
expect(company.audits.first.action).to eq("create")
|
530
|
+
end
|
531
|
+
|
532
|
+
context "after creating" do
|
533
|
+
it "updating / touching nested resource shouldn't save touch audit on parent object" do
|
534
|
+
expect { company.touch(:type) }.not_to change(user.audits, :count)
|
535
|
+
expect { company.update(type: "test") }.not_to change(user.audits, :count)
|
536
|
+
end
|
537
|
+
|
538
|
+
it "updating / touching parent object shouldn't save previous data" do
|
539
|
+
expect { user.touch(:suspended_at) }.to change(user.audits, :count).from(1).to(2)
|
540
|
+
expect(user.audits.last.action).to eq("update")
|
541
|
+
expect(user.audits.last.audited_changes.keys).to eq(%w[suspended_at])
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
context "after updating" do
|
546
|
+
it "changing nested resource shouldn't audit owner" do
|
547
|
+
expect { user.update(username: "test") }.to change(user.audits, :count).from(1).to(2)
|
548
|
+
expect { company.update(type: "test") }.not_to change(user.audits, :count)
|
549
|
+
|
550
|
+
expect { user.touch(:suspended_at) }.to change(user.audits, :count).from(2).to(3)
|
551
|
+
expect { company.update(type: "another_test") }.not_to change(user.audits, :count)
|
552
|
+
end
|
553
|
+
end
|
374
554
|
end
|
375
555
|
end
|
376
556
|
end
|
@@ -383,7 +563,7 @@ describe Audited::Auditor do
|
|
383
563
|
it "should save an audit" do
|
384
564
|
expect {
|
385
565
|
@user.destroy
|
386
|
-
}.to change(
|
566
|
+
}.to change(Audited::Audit, :count)
|
387
567
|
|
388
568
|
expect(@user.audits.size).to eq(2)
|
389
569
|
end
|
@@ -391,7 +571,7 @@ describe Audited::Auditor do
|
|
391
571
|
it "should set the action to 'destroy'" do
|
392
572
|
@user.destroy
|
393
573
|
|
394
|
-
expect(@user.audits.last.action).to eq(
|
574
|
+
expect(@user.audits.last.action).to eq("destroy")
|
395
575
|
expect(Audited::Audit.destroys.order(:id).last).to eq(@user.audits.last)
|
396
576
|
expect(@user.audits.destroys.last).to eq(@user.audits.last)
|
397
577
|
end
|
@@ -416,11 +596,11 @@ describe Audited::Auditor do
|
|
416
596
|
end
|
417
597
|
|
418
598
|
it "should not save an audit if only specified on create/update" do
|
419
|
-
on_create_update = Models::ActiveRecord::OnCreateUpdate.create!(
|
599
|
+
on_create_update = Models::ActiveRecord::OnCreateUpdate.create!(name: "Bart")
|
420
600
|
|
421
601
|
expect {
|
422
602
|
on_create_update.destroy
|
423
|
-
}.to_not change(
|
603
|
+
}.to_not change(Audited::Audit, :count)
|
424
604
|
end
|
425
605
|
|
426
606
|
it "should audit dependent destructions" do
|
@@ -429,9 +609,9 @@ describe Audited::Auditor do
|
|
429
609
|
|
430
610
|
expect {
|
431
611
|
owner.destroy
|
432
|
-
}.to change(
|
612
|
+
}.to change(Audited::Audit, :count)
|
433
613
|
|
434
|
-
expect(company.audits.map { |a| a.action }).to eq([
|
614
|
+
expect(company.audits.map { |a| a.action }).to eq(["create", "destroy"])
|
435
615
|
end
|
436
616
|
end
|
437
617
|
|
@@ -443,20 +623,20 @@ describe Audited::Auditor do
|
|
443
623
|
user.destroy
|
444
624
|
}.to_not raise_error
|
445
625
|
|
446
|
-
expect(
|
626
|
+
expect(user.audits).to be_empty
|
447
627
|
end
|
448
628
|
end
|
449
629
|
|
450
630
|
describe "associated with" do
|
451
|
-
let(:owner) { Models::ActiveRecord::Owner.create(name:
|
452
|
-
let(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name:
|
631
|
+
let(:owner) { Models::ActiveRecord::Owner.create(name: "Models::ActiveRecord::Owner") }
|
632
|
+
let(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name: "The auditors", owner: owner) }
|
453
633
|
|
454
634
|
it "should record the associated object on create" do
|
455
635
|
expect(owned_company.audits.first.associated).to eq(owner)
|
456
636
|
end
|
457
637
|
|
458
638
|
it "should store the associated object on update" do
|
459
|
-
owned_company.update_attribute(:name,
|
639
|
+
owned_company.update_attribute(:name, "The Auditors")
|
460
640
|
expect(owned_company.audits.last.associated).to eq(owner)
|
461
641
|
end
|
462
642
|
|
@@ -467,8 +647,8 @@ describe Audited::Auditor do
|
|
467
647
|
end
|
468
648
|
|
469
649
|
describe "has associated audits" do
|
470
|
-
let!(:owner) { Models::ActiveRecord::Owner.create!(name:
|
471
|
-
let!(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name:
|
650
|
+
let!(:owner) { Models::ActiveRecord::Owner.create!(name: "Models::ActiveRecord::Owner") }
|
651
|
+
let!(:owned_company) { Models::ActiveRecord::OwnedCompany.create!(name: "The auditors", owner: owner) }
|
472
652
|
|
473
653
|
it "should list the associated audits" do
|
474
654
|
expect(owner.associated_audits.length).to eq(1)
|
@@ -492,7 +672,7 @@ describe Audited::Auditor do
|
|
492
672
|
it "should delete old audits when keeped amount exceeded" do
|
493
673
|
stub_global_max_audits(2) do
|
494
674
|
user = create_versions(2)
|
495
|
-
user.update(name:
|
675
|
+
user.update(name: "John")
|
496
676
|
expect(user.audits.pluck(:version)).to eq([2, 3])
|
497
677
|
end
|
498
678
|
end
|
@@ -500,35 +680,35 @@ describe Audited::Auditor do
|
|
500
680
|
it "should not delete old audits when keeped amount not exceeded" do
|
501
681
|
stub_global_max_audits(3) do
|
502
682
|
user = create_versions(2)
|
503
|
-
user.update(name:
|
683
|
+
user.update(name: "John")
|
504
684
|
expect(user.audits.pluck(:version)).to eq([1, 2, 3])
|
505
685
|
end
|
506
686
|
end
|
507
687
|
|
508
688
|
it "should delete old extra audits after introducing limit" do
|
509
689
|
stub_global_max_audits(nil) do
|
510
|
-
user = Models::ActiveRecord::User.create!(name:
|
511
|
-
user.update!(name:
|
512
|
-
user.update!(name:
|
690
|
+
user = Models::ActiveRecord::User.create!(name: "Brandon", username: "brandon")
|
691
|
+
user.update!(name: "Foobar")
|
692
|
+
user.update!(name: "Awesome", username: "keepers")
|
513
693
|
user.update!(activated: true)
|
514
694
|
|
515
695
|
Audited.max_audits = 3
|
516
696
|
Models::ActiveRecord::User.send(:normalize_audited_options)
|
517
|
-
user.update!(favourite_device:
|
697
|
+
user.update!(favourite_device: "Android Phone")
|
518
698
|
audits = user.audits
|
519
699
|
|
520
700
|
expect(audits.count).to eq(3)
|
521
|
-
expect(audits[0].audited_changes).to include({
|
522
|
-
expect(audits[1].audited_changes).to eq({
|
523
|
-
expect(audits[2].audited_changes).to eq({
|
701
|
+
expect(audits[0].audited_changes).to include({"name" => ["Foobar", "Awesome"], "username" => ["brandon", "keepers"]})
|
702
|
+
expect(audits[1].audited_changes).to eq({"activated" => [nil, true]})
|
703
|
+
expect(audits[2].audited_changes).to eq({"favourite_device" => [nil, "Android Phone"]})
|
524
704
|
end
|
525
705
|
end
|
526
706
|
|
527
707
|
it "should add comment line for combined audit" do
|
528
708
|
stub_global_max_audits(2) do
|
529
|
-
user = Models::ActiveRecord::User.create!(name:
|
530
|
-
user.update(name:
|
531
|
-
user.update(name:
|
709
|
+
user = Models::ActiveRecord::User.create!(name: "Foobar 1")
|
710
|
+
user.update(name: "Foobar 2", audit_comment: "First audit comment")
|
711
|
+
user.update(name: "Foobar 3", audit_comment: "Second audit comment")
|
532
712
|
expect(user.audits.first.comment).to match(/First audit comment.+is the result of multiple/m)
|
533
713
|
end
|
534
714
|
end
|
@@ -548,10 +728,10 @@ describe Audited::Auditor do
|
|
548
728
|
end
|
549
729
|
|
550
730
|
describe "revisions" do
|
551
|
-
let(
|
731
|
+
let(:user) { create_versions }
|
552
732
|
|
553
733
|
it "should return an Array of Users" do
|
554
|
-
expect(user.revisions).to be_a_kind_of(
|
734
|
+
expect(user.revisions).to be_a_kind_of(Array)
|
555
735
|
user.revisions.each { |version| expect(version).to be_a_kind_of Models::ActiveRecord::User }
|
556
736
|
end
|
557
737
|
|
@@ -560,38 +740,38 @@ describe Audited::Auditor do
|
|
560
740
|
end
|
561
741
|
|
562
742
|
it "should have one revision for each audit" do
|
563
|
-
expect(user.audits.size).to eql(
|
743
|
+
expect(user.audits.size).to eql(user.revisions.size)
|
564
744
|
end
|
565
745
|
|
566
746
|
it "should set the attributes for each revision" do
|
567
|
-
u = Models::ActiveRecord::User.create(name:
|
568
|
-
u.update! name:
|
569
|
-
u.update! name:
|
747
|
+
u = Models::ActiveRecord::User.create(name: "Brandon", username: "brandon")
|
748
|
+
u.update! name: "Foobar"
|
749
|
+
u.update! name: "Awesome", username: "keepers"
|
570
750
|
|
571
751
|
expect(u.revisions.size).to eql(3)
|
572
752
|
|
573
|
-
expect(u.revisions[0].name).to eql(
|
574
|
-
expect(u.revisions[0].username).to eql(
|
753
|
+
expect(u.revisions[0].name).to eql("Brandon")
|
754
|
+
expect(u.revisions[0].username).to eql("brandon")
|
575
755
|
|
576
|
-
expect(u.revisions[1].name).to eql(
|
577
|
-
expect(u.revisions[1].username).to eql(
|
756
|
+
expect(u.revisions[1].name).to eql("Foobar")
|
757
|
+
expect(u.revisions[1].username).to eql("brandon")
|
578
758
|
|
579
|
-
expect(u.revisions[2].name).to eql(
|
580
|
-
expect(u.revisions[2].username).to eql(
|
759
|
+
expect(u.revisions[2].name).to eql("Awesome")
|
760
|
+
expect(u.revisions[2].username).to eql("keepers")
|
581
761
|
end
|
582
762
|
|
583
763
|
it "access to only recent revisions" do
|
584
|
-
u = Models::ActiveRecord::User.create(name:
|
585
|
-
u.update! name:
|
586
|
-
u.update! name:
|
764
|
+
u = Models::ActiveRecord::User.create(name: "Brandon", username: "brandon")
|
765
|
+
u.update! name: "Foobar"
|
766
|
+
u.update! name: "Awesome", username: "keepers"
|
587
767
|
|
588
768
|
expect(u.revisions(2).size).to eq(2)
|
589
769
|
|
590
|
-
expect(u.revisions(2)[0].name).to eq(
|
591
|
-
expect(u.revisions(2)[0].username).to eq(
|
770
|
+
expect(u.revisions(2)[0].name).to eq("Foobar")
|
771
|
+
expect(u.revisions(2)[0].username).to eq("brandon")
|
592
772
|
|
593
|
-
expect(u.revisions(2)[1].name).to eq(
|
594
|
-
expect(u.revisions(2)[1].username).to eq(
|
773
|
+
expect(u.revisions(2)[1].name).to eq("Awesome")
|
774
|
+
expect(u.revisions(2)[1].username).to eq("keepers")
|
595
775
|
end
|
596
776
|
|
597
777
|
it "should be empty if no audits exist" do
|
@@ -600,13 +780,13 @@ describe Audited::Auditor do
|
|
600
780
|
end
|
601
781
|
|
602
782
|
it "should ignore attributes that have been deleted" do
|
603
|
-
user.audits.last.update! audited_changes: {old_attribute:
|
783
|
+
user.audits.last.update! audited_changes: {old_attribute: "old value"}
|
604
784
|
expect { user.revisions }.to_not raise_error
|
605
785
|
end
|
606
786
|
end
|
607
787
|
|
608
788
|
describe "revisions" do
|
609
|
-
let(
|
789
|
+
let(:user) { create_versions(5) }
|
610
790
|
|
611
791
|
it "should maintain identity" do
|
612
792
|
expect(user.revision(1)).to eq(user)
|
@@ -614,15 +794,15 @@ describe Audited::Auditor do
|
|
614
794
|
|
615
795
|
it "should find the given revision" do
|
616
796
|
revision = user.revision(3)
|
617
|
-
expect(revision).to be_a_kind_of(
|
797
|
+
expect(revision).to be_a_kind_of(Models::ActiveRecord::User)
|
618
798
|
expect(revision.audit_version).to eq(3)
|
619
|
-
expect(revision.name).to eq(
|
799
|
+
expect(revision.name).to eq("Foobar 3")
|
620
800
|
end
|
621
801
|
|
622
802
|
it "should find the previous revision with :previous" do
|
623
803
|
revision = user.revision(:previous)
|
624
804
|
expect(revision.audit_version).to eq(4)
|
625
|
-
#expect(revision).to eq(user.revision(4))
|
805
|
+
# expect(revision).to eq(user.revision(4))
|
626
806
|
expect(revision.attributes).to eq(user.revision(4).attributes)
|
627
807
|
end
|
628
808
|
|
@@ -633,7 +813,7 @@ describe Audited::Auditor do
|
|
633
813
|
end
|
634
814
|
|
635
815
|
it "should be able to set protected attributes" do
|
636
|
-
u = Models::ActiveRecord::User.create(name:
|
816
|
+
u = Models::ActiveRecord::User.create(name: "Brandon")
|
637
817
|
u.update_attribute :logins, 1
|
638
818
|
u.update_attribute :logins, 2
|
639
819
|
|
@@ -643,23 +823,23 @@ describe Audited::Auditor do
|
|
643
823
|
end
|
644
824
|
|
645
825
|
it "should set attributes directly" do
|
646
|
-
u = Models::ActiveRecord::User.create(name:
|
647
|
-
expect(u.revision(1).name).to eq(
|
826
|
+
u = Models::ActiveRecord::User.create(name: "<Joe>")
|
827
|
+
expect(u.revision(1).name).to eq("<Joe>")
|
648
828
|
end
|
649
829
|
|
650
830
|
it "should set the attributes for each revision" do
|
651
|
-
u = Models::ActiveRecord::User.create(name:
|
652
|
-
u.update! name:
|
653
|
-
u.update! name:
|
831
|
+
u = Models::ActiveRecord::User.create(name: "Brandon", username: "brandon")
|
832
|
+
u.update! name: "Foobar"
|
833
|
+
u.update! name: "Awesome", username: "keepers"
|
654
834
|
|
655
|
-
expect(u.revision(3).name).to eq(
|
656
|
-
expect(u.revision(3).username).to eq(
|
835
|
+
expect(u.revision(3).name).to eq("Awesome")
|
836
|
+
expect(u.revision(3).username).to eq("keepers")
|
657
837
|
|
658
|
-
expect(u.revision(2).name).to eq(
|
659
|
-
expect(u.revision(2).username).to eq(
|
838
|
+
expect(u.revision(2).name).to eq("Foobar")
|
839
|
+
expect(u.revision(2).username).to eq("brandon")
|
660
840
|
|
661
|
-
expect(u.revision(1).name).to eq(
|
662
|
-
expect(u.revision(1).username).to eq(
|
841
|
+
expect(u.revision(1).name).to eq("Brandon")
|
842
|
+
expect(u.revision(1).username).to eq("brandon")
|
663
843
|
end
|
664
844
|
|
665
845
|
it "should correctly restore revision with enum" do
|
@@ -690,34 +870,42 @@ describe Audited::Auditor do
|
|
690
870
|
it "should record new audit when saving revision" do
|
691
871
|
expect {
|
692
872
|
user.revision(1).save!
|
693
|
-
}.to change(
|
873
|
+
}.to change(user.audits, :count).by(1)
|
694
874
|
end
|
695
875
|
|
696
876
|
it "should re-insert destroyed records" do
|
697
877
|
user.destroy
|
698
878
|
expect {
|
699
879
|
user.revision(1).save!
|
700
|
-
}.to change(
|
880
|
+
}.to change(Models::ActiveRecord::User, :count).by(1)
|
701
881
|
end
|
702
882
|
|
703
883
|
it "should return nil for values greater than the number of revisions" do
|
704
884
|
expect(user.revision(user.revisions.count + 1)).to be_nil
|
705
885
|
end
|
886
|
+
|
887
|
+
it "should work with array attributes" do
|
888
|
+
u = Models::ActiveRecord::User.create!(phone_numbers: ["+1 800-444-4444"])
|
889
|
+
u.update!(phone_numbers: ["+1 804-222-1111", "+1 317 222-2222"])
|
890
|
+
|
891
|
+
expect(u.revision(0).phone_numbers).to eq(["+1 804-222-1111", "+1 317 222-2222"])
|
892
|
+
expect(u.revision(1).phone_numbers).to eq(["+1 800-444-4444"])
|
893
|
+
end
|
706
894
|
end
|
707
895
|
|
708
896
|
describe "revision_at" do
|
709
|
-
let(
|
897
|
+
let(:user) { create_user }
|
710
898
|
|
711
899
|
it "should find the latest revision before the given time" do
|
712
900
|
audit = user.audits.first
|
713
901
|
audit.created_at = 1.hour.ago
|
714
902
|
audit.save!
|
715
|
-
user.update! name:
|
716
|
-
expect(user.revision_at(
|
903
|
+
user.update! name: "updated"
|
904
|
+
expect(user.revision_at(2.minutes.ago).audit_version).to eq(1)
|
717
905
|
end
|
718
906
|
|
719
907
|
it "should be nil if given a time before audits" do
|
720
|
-
expect(user.revision_at(
|
908
|
+
expect(user.revision_at(1.week.ago)).to be_nil
|
721
909
|
end
|
722
910
|
end
|
723
911
|
|
@@ -733,6 +921,19 @@ describe Audited::Auditor do
|
|
733
921
|
expect(owner.own_and_associated_audits).to match_array(owner.audits + company.audits)
|
734
922
|
end
|
735
923
|
|
924
|
+
it "should return audits for STI classes" do
|
925
|
+
# Where parent is STI
|
926
|
+
sti_company = Models::ActiveRecord::Company::STICompany.create!
|
927
|
+
sti_company.update!(name: "Collective Idea")
|
928
|
+
expect(sti_company.own_and_associated_audits).to match_array(sti_company.audits)
|
929
|
+
|
930
|
+
# Where associated is STI
|
931
|
+
owner = Models::ActiveRecord::Owner.create!
|
932
|
+
company = owner.companies.create! type: "Models::ActiveRecord::OwnedCompany::STICompany"
|
933
|
+
company.update!(name: "Collective Idea")
|
934
|
+
expect(owner.own_and_associated_audits).to match_array(owner.audits + company.audits)
|
935
|
+
end
|
936
|
+
|
736
937
|
it "should order audits by creation time" do
|
737
938
|
owner = Models::ActiveRecord::Owner.create!
|
738
939
|
first_audit = owner.audits.first
|
@@ -751,19 +952,32 @@ describe Audited::Auditor do
|
|
751
952
|
describe "without auditing" do
|
752
953
|
it "should not save an audit when calling #save_without_auditing" do
|
753
954
|
expect {
|
754
|
-
u = Models::ActiveRecord::User.new(name:
|
955
|
+
u = Models::ActiveRecord::User.new(name: "Brandon")
|
755
956
|
expect(u.save_without_auditing).to eq(true)
|
756
|
-
}.to_not change(
|
957
|
+
}.to_not change(Audited::Audit, :count)
|
757
958
|
end
|
758
959
|
|
759
960
|
it "should not save an audit inside of the #without_auditing block" do
|
760
961
|
expect {
|
761
|
-
Models::ActiveRecord::User.without_auditing { Models::ActiveRecord::User.create!(
|
762
|
-
}.to_not change(
|
962
|
+
Models::ActiveRecord::User.without_auditing { Models::ActiveRecord::User.create!(name: "Brandon") }
|
963
|
+
}.to_not change(Audited::Audit, :count)
|
964
|
+
end
|
965
|
+
|
966
|
+
context "when global audits are disabled" do
|
967
|
+
it "should re-enable class audits after #without_auditing block" do
|
968
|
+
Audited.auditing_enabled = false
|
969
|
+
Models::ActiveRecord::User.without_auditing {}
|
970
|
+
Audited.auditing_enabled = true
|
971
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eql(true)
|
972
|
+
end
|
763
973
|
end
|
764
974
|
|
765
975
|
it "should reset auditing status even it raises an exception" do
|
766
|
-
|
976
|
+
begin
|
977
|
+
Models::ActiveRecord::User.without_auditing { raise }
|
978
|
+
rescue
|
979
|
+
nil
|
980
|
+
end
|
767
981
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
768
982
|
end
|
769
983
|
|
@@ -774,7 +988,7 @@ describe Audited::Auditor do
|
|
774
988
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
775
989
|
Models::ActiveRecord::User.without_auditing do
|
776
990
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
777
|
-
Models::ActiveRecord::User.create!(
|
991
|
+
Models::ActiveRecord::User.create!(name: "Bart")
|
778
992
|
sleep 1
|
779
993
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
780
994
|
end
|
@@ -784,13 +998,13 @@ describe Audited::Auditor do
|
|
784
998
|
t2 = Thread.new do
|
785
999
|
sleep 0.5
|
786
1000
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
787
|
-
Models::ActiveRecord::User.create!(
|
1001
|
+
Models::ActiveRecord::User.create!(name: "Lisa")
|
788
1002
|
end
|
789
1003
|
t1.join
|
790
1004
|
t2.join
|
791
1005
|
|
792
|
-
expect(Models::ActiveRecord::User.find_by_name(
|
793
|
-
expect(Models::ActiveRecord::User.find_by_name(
|
1006
|
+
expect(Models::ActiveRecord::User.find_by_name("Bart").audits.count).to eq(0)
|
1007
|
+
expect(Models::ActiveRecord::User.find_by_name("Lisa").audits.count).to eq(1)
|
794
1008
|
end
|
795
1009
|
|
796
1010
|
it "should not save an audit when auditing is globally disabled" do
|
@@ -804,7 +1018,7 @@ describe Audited::Auditor do
|
|
804
1018
|
Audited.auditing_enabled = true
|
805
1019
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
806
1020
|
|
807
|
-
user.update!(name:
|
1021
|
+
user.update!(name: "Test")
|
808
1022
|
expect(user.audits.count).to eq(1)
|
809
1023
|
Models::ActiveRecord::User.enable_auditing
|
810
1024
|
end
|
@@ -813,24 +1027,37 @@ describe Audited::Auditor do
|
|
813
1027
|
describe "with auditing" do
|
814
1028
|
it "should save an audit when calling #save_with_auditing" do
|
815
1029
|
expect {
|
816
|
-
u = Models::ActiveRecord::User.new(name:
|
1030
|
+
u = Models::ActiveRecord::User.new(name: "Brandon")
|
817
1031
|
Models::ActiveRecord::User.auditing_enabled = false
|
818
1032
|
expect(u.save_with_auditing).to eq(true)
|
819
1033
|
Models::ActiveRecord::User.auditing_enabled = true
|
820
|
-
}.to change(
|
1034
|
+
}.to change(Audited::Audit, :count).by(1)
|
821
1035
|
end
|
822
1036
|
|
823
1037
|
it "should save an audit inside of the #with_auditing block" do
|
824
1038
|
expect {
|
825
1039
|
Models::ActiveRecord::User.auditing_enabled = false
|
826
|
-
Models::ActiveRecord::User.with_auditing { Models::ActiveRecord::User.create!(
|
1040
|
+
Models::ActiveRecord::User.with_auditing { Models::ActiveRecord::User.create!(name: "Brandon") }
|
827
1041
|
Models::ActiveRecord::User.auditing_enabled = true
|
828
|
-
}.to change(
|
1042
|
+
}.to change(Audited::Audit, :count).by(1)
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
context "when global audits are disabled" do
|
1046
|
+
it "should re-enable class audits after #with_auditing block" do
|
1047
|
+
Audited.auditing_enabled = false
|
1048
|
+
Models::ActiveRecord::User.with_auditing {}
|
1049
|
+
Audited.auditing_enabled = true
|
1050
|
+
expect(Models::ActiveRecord::User.auditing_enabled).to eql(true)
|
1051
|
+
end
|
829
1052
|
end
|
830
1053
|
|
831
1054
|
it "should reset auditing status even it raises an exception" do
|
832
1055
|
Models::ActiveRecord::User.disable_auditing
|
833
|
-
|
1056
|
+
begin
|
1057
|
+
Models::ActiveRecord::User.with_auditing { raise }
|
1058
|
+
rescue
|
1059
|
+
nil
|
1060
|
+
end
|
834
1061
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
835
1062
|
Models::ActiveRecord::User.enable_auditing
|
836
1063
|
end
|
@@ -844,7 +1071,7 @@ describe Audited::Auditor do
|
|
844
1071
|
Models::ActiveRecord::User.with_auditing do
|
845
1072
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
846
1073
|
|
847
|
-
Models::ActiveRecord::User.create!(
|
1074
|
+
Models::ActiveRecord::User.create!(name: "Shaggy")
|
848
1075
|
sleep 1
|
849
1076
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
|
850
1077
|
end
|
@@ -856,74 +1083,81 @@ describe Audited::Auditor do
|
|
856
1083
|
sleep 0.5
|
857
1084
|
Models::ActiveRecord::User.disable_auditing
|
858
1085
|
expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
|
859
|
-
Models::ActiveRecord::User.create!(
|
1086
|
+
Models::ActiveRecord::User.create!(name: "Scooby")
|
860
1087
|
Models::ActiveRecord::User.enable_auditing
|
861
1088
|
end
|
862
1089
|
t1.join
|
863
1090
|
t2.join
|
864
1091
|
|
865
1092
|
Models::ActiveRecord::User.enable_auditing
|
866
|
-
expect(Models::ActiveRecord::User.find_by_name(
|
867
|
-
expect(Models::ActiveRecord::User.find_by_name(
|
1093
|
+
expect(Models::ActiveRecord::User.find_by_name("Shaggy").audits.count).to eq(1)
|
1094
|
+
expect(Models::ActiveRecord::User.find_by_name("Scooby").audits.count).to eq(0)
|
868
1095
|
end
|
869
1096
|
end
|
870
1097
|
|
871
1098
|
describe "comment required" do
|
872
|
-
|
873
1099
|
describe "on create" do
|
874
1100
|
it "should not validate when audit_comment is not supplied when initialized" do
|
875
|
-
expect(Models::ActiveRecord::CommentRequiredUser.new(name:
|
1101
|
+
expect(Models::ActiveRecord::CommentRequiredUser.new(name: "Foo")).not_to be_valid
|
876
1102
|
end
|
877
1103
|
|
878
1104
|
it "should not validate when audit_comment is not supplied trying to create" do
|
879
|
-
expect(Models::ActiveRecord::CommentRequiredUser.create(name:
|
1105
|
+
expect(Models::ActiveRecord::CommentRequiredUser.create(name: "Foo")).not_to be_valid
|
880
1106
|
end
|
881
1107
|
|
882
1108
|
it "should validate when audit_comment is supplied" do
|
883
|
-
expect(Models::ActiveRecord::CommentRequiredUser.create(name:
|
1109
|
+
expect(Models::ActiveRecord::CommentRequiredUser.create(name: "Foo", audit_comment: "Create")).to be_valid
|
884
1110
|
end
|
885
1111
|
|
886
1112
|
it "should validate when audit_comment is not supplied, and creating is not being audited" do
|
887
|
-
expect(Models::ActiveRecord::OnUpdateCommentRequiredUser.create(name:
|
888
|
-
expect(Models::ActiveRecord::OnDestroyCommentRequiredUser.create(name:
|
1113
|
+
expect(Models::ActiveRecord::OnUpdateCommentRequiredUser.create(name: "Foo")).to be_valid
|
1114
|
+
expect(Models::ActiveRecord::OnDestroyCommentRequiredUser.create(name: "Foo")).to be_valid
|
889
1115
|
end
|
890
1116
|
|
891
1117
|
it "should validate when audit_comment is not supplied, and auditing is disabled" do
|
892
1118
|
Models::ActiveRecord::CommentRequiredUser.disable_auditing
|
893
|
-
expect(Models::ActiveRecord::CommentRequiredUser.create(name:
|
1119
|
+
expect(Models::ActiveRecord::CommentRequiredUser.create(name: "Foo")).to be_valid
|
894
1120
|
Models::ActiveRecord::CommentRequiredUser.enable_auditing
|
895
1121
|
end
|
1122
|
+
|
1123
|
+
it "should validate when audit_comment is not supplied, and only excluded attributes changed" do
|
1124
|
+
expect(Models::ActiveRecord::CommentRequiredUser.new(password: "Foo")).to be_valid
|
1125
|
+
end
|
896
1126
|
end
|
897
1127
|
|
898
1128
|
describe "on update" do
|
899
|
-
let(
|
900
|
-
let(
|
901
|
-
let(
|
1129
|
+
let(:user) { Models::ActiveRecord::CommentRequiredUser.create!(audit_comment: "Create") }
|
1130
|
+
let(:on_create_user) { Models::ActiveRecord::OnDestroyCommentRequiredUser.create }
|
1131
|
+
let(:on_destroy_user) { Models::ActiveRecord::OnDestroyCommentRequiredUser.create }
|
902
1132
|
|
903
1133
|
it "should not validate when audit_comment is not supplied" do
|
904
|
-
expect(user.update(name:
|
1134
|
+
expect(user.update(name: "Test")).to eq(false)
|
905
1135
|
end
|
906
1136
|
|
907
1137
|
it "should validate when audit_comment is not supplied, and updating is not being audited" do
|
908
|
-
expect(on_create_user.update(name:
|
909
|
-
expect(on_destroy_user.update(name:
|
1138
|
+
expect(on_create_user.update(name: "Test")).to eq(true)
|
1139
|
+
expect(on_destroy_user.update(name: "Test")).to eq(true)
|
910
1140
|
end
|
911
1141
|
|
912
1142
|
it "should validate when audit_comment is supplied" do
|
913
|
-
expect(user.update(name:
|
1143
|
+
expect(user.update(name: "Test", audit_comment: "Update")).to eq(true)
|
914
1144
|
end
|
915
1145
|
|
916
1146
|
it "should validate when audit_comment is not supplied, and auditing is disabled" do
|
917
1147
|
Models::ActiveRecord::CommentRequiredUser.disable_auditing
|
918
|
-
expect(user.update(name:
|
1148
|
+
expect(user.update(name: "Test")).to eq(true)
|
919
1149
|
Models::ActiveRecord::CommentRequiredUser.enable_auditing
|
920
1150
|
end
|
1151
|
+
|
1152
|
+
it "should validate when audit_comment is not supplied, and only excluded attributes changed" do
|
1153
|
+
expect(user.update(password: "Test")).to eq(true)
|
1154
|
+
end
|
921
1155
|
end
|
922
1156
|
|
923
1157
|
describe "on destroy" do
|
924
|
-
let(
|
925
|
-
let(
|
926
|
-
let(
|
1158
|
+
let(:user) { Models::ActiveRecord::CommentRequiredUser.create!(audit_comment: "Create") }
|
1159
|
+
let(:on_create_user) { Models::ActiveRecord::OnCreateCommentRequiredUser.create!(audit_comment: "Create") }
|
1160
|
+
let(:on_update_user) { Models::ActiveRecord::OnUpdateCommentRequiredUser.create }
|
927
1161
|
|
928
1162
|
it "should not validate when audit_comment is not supplied" do
|
929
1163
|
expect(user.destroy).to eq(false)
|
@@ -945,41 +1179,38 @@ describe Audited::Auditor do
|
|
945
1179
|
Models::ActiveRecord::CommentRequiredUser.enable_auditing
|
946
1180
|
end
|
947
1181
|
end
|
948
|
-
|
949
1182
|
end
|
950
1183
|
|
951
1184
|
describe "no update with comment only" do
|
952
|
-
let(
|
1185
|
+
let(:user) { Models::ActiveRecord::NoUpdateWithCommentOnlyUser.create }
|
953
1186
|
|
954
1187
|
it "does not create an audit when only an audit_comment is present" do
|
955
1188
|
user.audit_comment = "Comment"
|
956
|
-
expect { user.save! }.to_not change(
|
1189
|
+
expect { user.save! }.to_not change(Audited::Audit, :count)
|
957
1190
|
end
|
958
|
-
|
959
1191
|
end
|
960
1192
|
|
961
1193
|
describe "attr_protected and attr_accessible" do
|
962
|
-
|
963
1194
|
it "should not raise error when attr_accessible is set and protected is false" do
|
964
1195
|
expect {
|
965
|
-
Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name:
|
1196
|
+
Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name: "No fail!")
|
966
1197
|
}.to_not raise_error
|
967
1198
|
end
|
968
1199
|
|
969
1200
|
it "should not rause an error when attr_accessible is declared before audited" do
|
970
1201
|
expect {
|
971
|
-
Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name:
|
1202
|
+
Models::ActiveRecord::AccessibleAfterDeclarationUser.new(name: "No fail!")
|
972
1203
|
}.to_not raise_error
|
973
1204
|
end
|
974
1205
|
end
|
975
1206
|
|
976
1207
|
describe "audit_as" do
|
977
|
-
let(
|
1208
|
+
let(:user) { Models::ActiveRecord::User.create name: "Testing" }
|
978
1209
|
|
979
1210
|
it "should record user objects" do
|
980
|
-
Models::ActiveRecord::Company.audit_as(
|
981
|
-
company = Models::ActiveRecord::Company.create name:
|
982
|
-
company.update! name:
|
1211
|
+
Models::ActiveRecord::Company.audit_as(user) do
|
1212
|
+
company = Models::ActiveRecord::Company.create name: "The auditors"
|
1213
|
+
company.update! name: "The Auditors"
|
983
1214
|
|
984
1215
|
company.audits.each do |audit|
|
985
1216
|
expect(audit.user).to eq(user)
|
@@ -988,9 +1219,9 @@ describe Audited::Auditor do
|
|
988
1219
|
end
|
989
1220
|
|
990
1221
|
it "should record usernames" do
|
991
|
-
Models::ActiveRecord::Company.audit_as(
|
992
|
-
company = Models::ActiveRecord::Company.create name:
|
993
|
-
company.update! name:
|
1222
|
+
Models::ActiveRecord::Company.audit_as(user.name) do
|
1223
|
+
company = Models::ActiveRecord::Company.create name: "The auditors"
|
1224
|
+
company.update! name: "The Auditors"
|
994
1225
|
|
995
1226
|
company.audits.each do |audit|
|
996
1227
|
expect(audit.user).to eq(user.name)
|
@@ -1000,7 +1231,7 @@ describe Audited::Auditor do
|
|
1000
1231
|
end
|
1001
1232
|
|
1002
1233
|
describe "after_audit" do
|
1003
|
-
let(
|
1234
|
+
let(:user) { Models::ActiveRecord::UserWithAfterAudit.new }
|
1004
1235
|
|
1005
1236
|
it "should invoke after_audit callback on create" do
|
1006
1237
|
expect(user.bogus_attr).to be_nil
|
@@ -1010,7 +1241,7 @@ describe Audited::Auditor do
|
|
1010
1241
|
end
|
1011
1242
|
|
1012
1243
|
describe "around_audit" do
|
1013
|
-
let(
|
1244
|
+
let(:user) { Models::ActiveRecord::UserWithAfterAudit.new }
|
1014
1245
|
|
1015
1246
|
it "should invoke around_audit callback on create" do
|
1016
1247
|
expect(user.around_attr).to be_nil
|
@@ -1021,13 +1252,13 @@ describe Audited::Auditor do
|
|
1021
1252
|
|
1022
1253
|
describe "STI auditing" do
|
1023
1254
|
it "should correctly disable auditing when using STI" do
|
1024
|
-
company = Models::ActiveRecord::Company::STICompany.create name:
|
1255
|
+
company = Models::ActiveRecord::Company::STICompany.create name: "The auditors"
|
1025
1256
|
expect(company.type).to eq("Models::ActiveRecord::Company::STICompany")
|
1026
1257
|
expect {
|
1027
1258
|
Models::ActiveRecord::Company.auditing_enabled = false
|
1028
|
-
company.update! name:
|
1259
|
+
company.update! name: "STI auditors"
|
1029
1260
|
Models::ActiveRecord::Company.auditing_enabled = true
|
1030
|
-
}.to_not change(
|
1261
|
+
}.to_not change(Audited::Audit, :count)
|
1031
1262
|
end
|
1032
1263
|
end
|
1033
1264
|
end
|