audited 5.2.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +22 -5
- data/Appraisals +10 -0
- data/CHANGELOG.md +36 -0
- data/README.md +3 -2
- data/gemfiles/rails50.gemfile +1 -0
- data/gemfiles/rails51.gemfile +1 -0
- data/gemfiles/rails52.gemfile +1 -0
- data/gemfiles/rails71.gemfile +10 -0
- data/lib/audited/audit.rb +6 -2
- data/lib/audited/auditor.rb +25 -3
- data/lib/audited/version.rb +1 -1
- data/lib/audited.rb +4 -8
- data/spec/audited/audit_spec.rb +1 -1
- data/spec/audited/auditor_spec.rb +108 -4
- data/spec/audited_spec.rb +2 -6
- data/spec/rails_app/config/application.rb +24 -1
- data/spec/support/active_record/models.rb +18 -2
- metadata +20 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 276c472a6d93d971c65197a821d22f7488c6b7495a933428faece47530131e96
|
|
4
|
+
data.tar.gz: 6cb8e7d470900e358fe3a1e8382f5c55385bee8a6b69bad2bd59acb3ac6b2420
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e47432c90d81c5b009a2fdab3b720891cb00166adb285e4682c926e1f362c92897bb7f986295e25478c2cce09b29e5a05c956dc43af45c7c9dec6ba4b3e24df4
|
|
7
|
+
data.tar.gz: 60d2cc638562195e03cfab4f7e7825f7f7c90039b8a0a2d3f6de13e3778f6a6a89cd46574a951bfc5961649ef0fee3272c09b70111de82d3164bb40caceb797d
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
name: CI
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
pull_request
|
|
5
|
-
push
|
|
6
|
-
branches:
|
|
7
|
-
- main
|
|
4
|
+
- pull_request
|
|
5
|
+
- push
|
|
8
6
|
|
|
9
7
|
jobs:
|
|
10
8
|
build:
|
|
@@ -12,7 +10,7 @@ jobs:
|
|
|
12
10
|
strategy:
|
|
13
11
|
fail-fast: false
|
|
14
12
|
matrix:
|
|
15
|
-
ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1]
|
|
13
|
+
ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2]
|
|
16
14
|
appraisal:
|
|
17
15
|
- rails50
|
|
18
16
|
- rails51
|
|
@@ -20,6 +18,7 @@ jobs:
|
|
|
20
18
|
- rails60
|
|
21
19
|
- rails61
|
|
22
20
|
- rails70
|
|
21
|
+
- rails71
|
|
23
22
|
db: [POSTGRES, MYSQL, SQLITE]
|
|
24
23
|
exclude:
|
|
25
24
|
# MySQL has issues on Ruby 2.3
|
|
@@ -43,6 +42,8 @@ jobs:
|
|
|
43
42
|
ruby: 3.0
|
|
44
43
|
- appraisal: rails50
|
|
45
44
|
ruby: 3.1
|
|
45
|
+
- appraisal: rails50
|
|
46
|
+
ruby: 3.2
|
|
46
47
|
|
|
47
48
|
# Rails 5.1 supports Ruby 2.2-2.5
|
|
48
49
|
- appraisal: rails51
|
|
@@ -53,6 +54,8 @@ jobs:
|
|
|
53
54
|
ruby: 3.0
|
|
54
55
|
- appraisal: rails51
|
|
55
56
|
ruby: 3.1
|
|
57
|
+
- appraisal: rails51
|
|
58
|
+
ruby: 3.2
|
|
56
59
|
|
|
57
60
|
# Rails 5.2 supports Ruby 2.2-2.5
|
|
58
61
|
- appraisal: rails52
|
|
@@ -63,6 +66,8 @@ jobs:
|
|
|
63
66
|
ruby: 3.0
|
|
64
67
|
- appraisal: rails52
|
|
65
68
|
ruby: 3.1
|
|
69
|
+
- appraisal: rails52
|
|
70
|
+
ruby: 3.2
|
|
66
71
|
|
|
67
72
|
# Rails 6.0 supports Ruby 2.5-2.7
|
|
68
73
|
- appraisal: rails60
|
|
@@ -73,6 +78,8 @@ jobs:
|
|
|
73
78
|
ruby: 3.0
|
|
74
79
|
- appraisal: rails60
|
|
75
80
|
ruby: 3.1
|
|
81
|
+
- appraisal: rails60
|
|
82
|
+
ruby: 3.2
|
|
76
83
|
|
|
77
84
|
# Rails 6.1 supports Ruby 2.5+
|
|
78
85
|
- appraisal: rails61
|
|
@@ -90,6 +97,16 @@ jobs:
|
|
|
90
97
|
- appraisal: rails70
|
|
91
98
|
ruby: 2.6
|
|
92
99
|
|
|
100
|
+
# Rails 7.1 supports Ruby 2.7+
|
|
101
|
+
- appraisal: rails71
|
|
102
|
+
ruby: 2.3
|
|
103
|
+
- appraisal: rails71
|
|
104
|
+
ruby: 2.4
|
|
105
|
+
- appraisal: rails71
|
|
106
|
+
ruby: 2.5
|
|
107
|
+
- appraisal: rails71
|
|
108
|
+
ruby: 2.6
|
|
109
|
+
|
|
93
110
|
services:
|
|
94
111
|
postgres:
|
|
95
112
|
image: postgres
|
data/Appraisals
CHANGED
|
@@ -7,6 +7,7 @@ appraise "rails50" do
|
|
|
7
7
|
gem "pg", ">= 0.18", "< 2.0"
|
|
8
8
|
gem "sqlite3", "~> 1.3.6"
|
|
9
9
|
gem "psych", "~> 3.1"
|
|
10
|
+
gem "loofah", "2.20.0"
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
appraise "rails51" do
|
|
@@ -15,6 +16,7 @@ appraise "rails51" do
|
|
|
15
16
|
gem "pg", ">= 0.18", "< 2.0"
|
|
16
17
|
gem "sqlite3", "~> 1.3.6"
|
|
17
18
|
gem "psych", "~> 3.1"
|
|
19
|
+
gem "loofah", "2.20.0"
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
appraise "rails52" do
|
|
@@ -23,6 +25,7 @@ appraise "rails52" do
|
|
|
23
25
|
gem "pg", ">= 0.18", "< 2.0"
|
|
24
26
|
gem "sqlite3", "~> 1.3.6"
|
|
25
27
|
gem "psych", "~> 3.1"
|
|
28
|
+
gem "loofah", "2.20.0"
|
|
26
29
|
end
|
|
27
30
|
|
|
28
31
|
appraise "rails60" do
|
|
@@ -45,3 +48,10 @@ appraise "rails70" do
|
|
|
45
48
|
gem "pg", ">= 1.1"
|
|
46
49
|
gem "sqlite3", ">= 1.4"
|
|
47
50
|
end
|
|
51
|
+
|
|
52
|
+
appraise "rails71" do
|
|
53
|
+
gem "rails", ">= 7.1.0.beta1", "< 7.2"
|
|
54
|
+
gem "mysql2", ">= 0.4.4"
|
|
55
|
+
gem "pg", ">= 1.1"
|
|
56
|
+
gem "sqlite3", ">= 1.4"
|
|
57
|
+
end
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Audited ChangeLog
|
|
2
2
|
|
|
3
|
+
## 5.4.0 (2023-09-30)
|
|
4
|
+
|
|
5
|
+
- Add Rails 7.1 support - @yuki24
|
|
6
|
+
[#686](https://github.com/collectiveidea/audited/pull/686)
|
|
7
|
+
|
|
8
|
+
## 5.3.3 (2023-03-24)
|
|
9
|
+
|
|
10
|
+
- Use RequestStore instead of Thread.current for thread-safe requests - @tiagocassio
|
|
11
|
+
[#669](https://github.com/collectiveidea/audited/pull/669)
|
|
12
|
+
- Clean up Touch audits - @mcyoung, @akostadinov
|
|
13
|
+
[#668](https://github.com/collectiveidea/audited/pull/668)
|
|
14
|
+
|
|
15
|
+
## 5.3.2 (2023-02-22)
|
|
16
|
+
|
|
17
|
+
- Touch audit bug fixes - @mcyoung
|
|
18
|
+
[#662](https://github.com/collectiveidea/audited/pull/662)
|
|
19
|
+
|
|
20
|
+
## 5.3.1 (2023-02-21)
|
|
21
|
+
|
|
22
|
+
- Ensure touch support doesn't cause double audits - @mcyoung
|
|
23
|
+
[#660](https://github.com/collectiveidea/audited/pull/660)
|
|
24
|
+
- Testing Improvements - @vlad-psh
|
|
25
|
+
[#628](https://github.com/collectiveidea/audited/pull/628)
|
|
26
|
+
- Testing Improvements - @mcyoung
|
|
27
|
+
[#658](https://github.com/collectiveidea/audited/pull/658)
|
|
28
|
+
|
|
29
|
+
## 5.3.0 (2023-02-14)
|
|
30
|
+
|
|
31
|
+
- Audit touch calls - @mcyoung
|
|
32
|
+
[#657](https://github.com/collectiveidea/audited/pull/657)
|
|
33
|
+
- Allow using with Padrino and other non-Rails projects - @nicduke38degrees
|
|
34
|
+
[#655](https://github.com/collectiveidea/audited/pull/655)
|
|
35
|
+
- Testing updates - @jdufresne
|
|
36
|
+
[#652](https://github.com/collectiveidea/audited/pull/652)
|
|
37
|
+
[#653](https://github.com/collectiveidea/audited/pull/653)
|
|
38
|
+
|
|
3
39
|
## 5.2.0 (2023-01-23)
|
|
4
40
|
|
|
5
41
|
Improved
|
data/README.md
CHANGED
|
@@ -24,6 +24,7 @@ Audited supports and is [tested against](https://github.com/collectiveidea/audit
|
|
|
24
24
|
* 2.7
|
|
25
25
|
* 3.0
|
|
26
26
|
* 3.1
|
|
27
|
+
* 3.2
|
|
27
28
|
|
|
28
29
|
Audited may work just fine with a Ruby version not listed above, but we can't guarantee that it will. If you'd like to maintain a Ruby that isn't listed, please let us know with a [pull request](https://github.com/collectiveidea/audited/pulls).
|
|
29
30
|
|
|
@@ -36,7 +37,7 @@ Audited is currently ActiveRecord-only. In a previous life, Audited worked with
|
|
|
36
37
|
Add the gem to your Gemfile:
|
|
37
38
|
|
|
38
39
|
```ruby
|
|
39
|
-
gem "audited"
|
|
40
|
+
gem "audited"
|
|
40
41
|
```
|
|
41
42
|
|
|
42
43
|
And if you're using ```require: false``` you must add initializers like this:
|
|
@@ -237,7 +238,7 @@ class ApplicationController < ActionController::Base
|
|
|
237
238
|
if current_user
|
|
238
239
|
current_user
|
|
239
240
|
else
|
|
240
|
-
'
|
|
241
|
+
'Alexander Fleming'
|
|
241
242
|
end
|
|
242
243
|
end
|
|
243
244
|
end
|
data/gemfiles/rails50.gemfile
CHANGED
data/gemfiles/rails51.gemfile
CHANGED
data/gemfiles/rails52.gemfile
CHANGED
data/lib/audited/audit.rb
CHANGED
|
@@ -49,7 +49,11 @@ module Audited
|
|
|
49
49
|
cattr_accessor :audited_class_names
|
|
50
50
|
self.audited_class_names = Set.new
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
if Rails.version >= "7.1"
|
|
53
|
+
serialize :audited_changes, coder: YAMLIfTextColumnType
|
|
54
|
+
else
|
|
55
|
+
serialize :audited_changes, YAMLIfTextColumnType
|
|
56
|
+
end
|
|
53
57
|
|
|
54
58
|
scope :ascending, -> { reorder(version: :asc) }
|
|
55
59
|
scope :descending, -> { reorder(version: :desc) }
|
|
@@ -174,7 +178,7 @@ module Audited
|
|
|
174
178
|
if action == "create"
|
|
175
179
|
self.version = 1
|
|
176
180
|
else
|
|
177
|
-
collection = (
|
|
181
|
+
collection = (ActiveRecord::VERSION::MAJOR >= 6) ? self.class.unscoped : self.class
|
|
178
182
|
max = collection.auditable_finder(auditable_id, auditable_type).maximum(:version) || 0
|
|
179
183
|
self.version = max + 1
|
|
180
184
|
end
|
data/lib/audited/auditor.rb
CHANGED
|
@@ -84,6 +84,7 @@ module Audited
|
|
|
84
84
|
|
|
85
85
|
after_create :audit_create if audited_options[:on].include?(:create)
|
|
86
86
|
before_update :audit_update if audited_options[:on].include?(:update)
|
|
87
|
+
after_touch :audit_touch if audited_options[:on].include?(:touch) && ::ActiveRecord::VERSION::MAJOR >= 6
|
|
87
88
|
before_destroy :audit_destroy if audited_options[:on].include?(:destroy)
|
|
88
89
|
|
|
89
90
|
# Define and set after_audit and around_audit callbacks. This might be useful if you want
|
|
@@ -230,8 +231,15 @@ module Audited
|
|
|
230
231
|
|
|
231
232
|
private
|
|
232
233
|
|
|
233
|
-
def audited_changes
|
|
234
|
-
all_changes =
|
|
234
|
+
def audited_changes(for_touch: false)
|
|
235
|
+
all_changes = if for_touch
|
|
236
|
+
previous_changes
|
|
237
|
+
elsif respond_to?(:changes_to_save)
|
|
238
|
+
changes_to_save
|
|
239
|
+
else
|
|
240
|
+
changes
|
|
241
|
+
end
|
|
242
|
+
|
|
235
243
|
filtered_changes = \
|
|
236
244
|
if audited_options[:only].present?
|
|
237
245
|
all_changes.slice(*self.class.audited_columns)
|
|
@@ -239,6 +247,13 @@ module Audited
|
|
|
239
247
|
all_changes.except(*self.class.non_audited_columns)
|
|
240
248
|
end
|
|
241
249
|
|
|
250
|
+
if for_touch && (last_audit = audits.last&.audited_changes)
|
|
251
|
+
filtered_changes.reject! do |k, v|
|
|
252
|
+
last_audit[k].to_json == v.to_json ||
|
|
253
|
+
last_audit[k].to_json == v[1].to_json
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
242
257
|
filtered_changes = redact_values(filtered_changes)
|
|
243
258
|
filtered_changes = filter_encrypted_attrs(filtered_changes)
|
|
244
259
|
filtered_changes = normalize_enum_changes(filtered_changes)
|
|
@@ -324,6 +339,13 @@ module Audited
|
|
|
324
339
|
end
|
|
325
340
|
end
|
|
326
341
|
|
|
342
|
+
def audit_touch
|
|
343
|
+
unless (changes = audited_changes(for_touch: true)).empty?
|
|
344
|
+
write_audit(action: "update", audited_changes: changes,
|
|
345
|
+
comment: audit_comment)
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
327
349
|
def audit_destroy
|
|
328
350
|
unless new_record?
|
|
329
351
|
write_audit(action: "destroy", audited_changes: audited_attributes,
|
|
@@ -474,7 +496,7 @@ module Audited
|
|
|
474
496
|
|
|
475
497
|
def normalize_audited_options
|
|
476
498
|
audited_options[:on] = Array.wrap(audited_options[:on])
|
|
477
|
-
audited_options[:on] = [:create, :update, :destroy] if audited_options[:on].empty?
|
|
499
|
+
audited_options[:on] = [:create, :update, :touch, :destroy] if audited_options[:on].empty?
|
|
478
500
|
audited_options[:only] = Array.wrap(audited_options[:only]).map(&:to_s)
|
|
479
501
|
audited_options[:except] = Array.wrap(audited_options[:except]).map(&:to_s)
|
|
480
502
|
max_audits = audited_options[:max_audits] || Audited.max_audits
|
data/lib/audited/version.rb
CHANGED
data/lib/audited.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "active_record"
|
|
4
|
+
require "request_store"
|
|
4
5
|
|
|
5
6
|
module Audited
|
|
6
7
|
class << self
|
|
@@ -21,16 +22,11 @@ module Audited
|
|
|
21
22
|
|
|
22
23
|
# remove audit_model in next major version it was only shortly present in 5.1.0
|
|
23
24
|
alias_method :audit_model, :audit_class
|
|
24
|
-
deprecate audit_model: "use Audited.audit_class instead of Audited.audit_model. This method will be removed."
|
|
25
|
+
deprecate audit_model: "use Audited.audit_class instead of Audited.audit_model. This method will be removed.",
|
|
26
|
+
deprecator: ActiveSupport::Deprecation.new('6.0.0', 'Audited')
|
|
25
27
|
|
|
26
28
|
def store
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if current_store_value.nil?
|
|
30
|
-
Thread.current.thread_variable_set(:audited_store, {})
|
|
31
|
-
else
|
|
32
|
-
current_store_value
|
|
33
|
-
end
|
|
29
|
+
RequestStore.store[:audited_store] ||= {}
|
|
34
30
|
end
|
|
35
31
|
|
|
36
32
|
def config
|
data/spec/audited/audit_spec.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
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
|
|
6
9
|
self.table_name = "companies"
|
|
@@ -143,7 +146,7 @@ describe Audited::Auditor do
|
|
|
143
146
|
end
|
|
144
147
|
|
|
145
148
|
it "should be configurable which attributes are not audited via ignored_attributes" do
|
|
146
|
-
Audited.ignored_attributes = ["delta", "top_secret", "created_at"]
|
|
149
|
+
Audited.ignored_attributes = ["delta", "top_secret", "created_at", "updated_at"]
|
|
147
150
|
|
|
148
151
|
expect(Secret.non_audited_columns).to include("delta", "top_secret", "created_at")
|
|
149
152
|
end
|
|
@@ -215,17 +218,25 @@ describe Audited::Auditor do
|
|
|
215
218
|
redacted = Audited::Auditor::AuditedInstanceMethods::REDACTED
|
|
216
219
|
user =
|
|
217
220
|
Models::ActiveRecord::UserMultipleRedactedAttributes.create(
|
|
218
|
-
password: "password"
|
|
219
|
-
ssn: 123456789
|
|
221
|
+
password: "password"
|
|
220
222
|
)
|
|
221
223
|
user.save!
|
|
222
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
|
|
223
226
|
expect(user.audits.last.audited_changes["ssn"]).to eq(redacted)
|
|
227
|
+
|
|
224
228
|
user.password = "new_password"
|
|
225
229
|
user.ssn = 987654321
|
|
226
230
|
user.save!
|
|
227
231
|
expect(user.audits.last.audited_changes["password"]).to eq([redacted, redacted])
|
|
228
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")
|
|
229
240
|
end
|
|
230
241
|
|
|
231
242
|
it "should redact columns in 'redacted' column with custom option" do
|
|
@@ -414,6 +425,99 @@ describe Audited::Auditor do
|
|
|
414
425
|
end
|
|
415
426
|
end
|
|
416
427
|
|
|
428
|
+
if ::ActiveRecord::VERSION::MAJOR >= 6
|
|
429
|
+
describe "on touch" do
|
|
430
|
+
before do
|
|
431
|
+
@user = create_user(name: "Brandon", status: :active)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
it "should save an audit" do
|
|
435
|
+
expect { @user.touch(:suspended_at) }.to change(Audited::Audit, :count).by(1)
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
it "should set the action to 'update'" do
|
|
439
|
+
@user.touch(:suspended_at)
|
|
440
|
+
expect(@user.audits.last.action).to eq("update")
|
|
441
|
+
expect(Audited::Audit.updates.order(:id).last).to eq(@user.audits.last)
|
|
442
|
+
expect(@user.audits.updates.last).to eq(@user.audits.last)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
it "should store the changed attributes" do
|
|
446
|
+
@user.touch(:suspended_at)
|
|
447
|
+
expect(@user.audits.last.audited_changes["suspended_at"][0]).to be_nil
|
|
448
|
+
expect(Time.parse(@user.audits.last.audited_changes["suspended_at"][1].to_s)).to be_within(2.seconds).of(Time.current)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
it "should store audit comment" do
|
|
452
|
+
@user.audit_comment = "Here exists a touch comment"
|
|
453
|
+
@user.touch(:suspended_at)
|
|
454
|
+
expect(@user.audits.last.action).to eq("update")
|
|
455
|
+
expect(@user.audits.last.comment).to eq("Here exists a touch comment")
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
it "should not save an audit if only specified on create/destroy" do
|
|
459
|
+
on_create_destroy = Models::ActiveRecord::OnCreateDestroyUser.create(name: "Bart")
|
|
460
|
+
expect {
|
|
461
|
+
on_create_destroy.touch(:suspended_at)
|
|
462
|
+
}.to_not change(Audited::Audit, :count)
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
it "should store an audit if touch is the only audit" do
|
|
466
|
+
on_touch = Models::ActiveRecord::OnTouchOnly.create(name: "Bart")
|
|
467
|
+
expect {
|
|
468
|
+
on_touch.update(name: "NotBart")
|
|
469
|
+
}.to_not change(Audited::Audit, :count)
|
|
470
|
+
expect {
|
|
471
|
+
on_touch.touch(:suspended_at)
|
|
472
|
+
}.to change(on_touch.audits, :count).from(0).to(1)
|
|
473
|
+
|
|
474
|
+
@user.audits.destroy_all
|
|
475
|
+
expect(@user.audits).to be_empty
|
|
476
|
+
expect {
|
|
477
|
+
@user.touch(:suspended_at)
|
|
478
|
+
}.to change(@user.audits, :count).from(0).to(1)
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
context "don't double audit" do
|
|
482
|
+
let(:user) { Models::ActiveRecord::Owner.create(name: "OwnerUser", suspended_at: 1.month.ago, companies_attributes: [{name: "OwnedCompany"}]) }
|
|
483
|
+
let(:company) { user.companies.first }
|
|
484
|
+
|
|
485
|
+
it "should only create 1 (create) audit for object" do
|
|
486
|
+
expect(user.audits.count).to eq(1)
|
|
487
|
+
expect(user.audits.first.action).to eq("create")
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
it "should only create 1 (create) audit for nested resource" do
|
|
491
|
+
expect(company.audits.count).to eq(1)
|
|
492
|
+
expect(company.audits.first.action).to eq("create")
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
context "after creating" do
|
|
496
|
+
it "updating / touching nested resource shouldn't save touch audit on parent object" do
|
|
497
|
+
expect { company.touch(:type) }.not_to change(user.audits, :count)
|
|
498
|
+
expect { company.update(type: "test") }.not_to change(user.audits, :count)
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
it "updating / touching parent object shouldn't save previous data" do
|
|
502
|
+
expect { user.touch(:suspended_at) }.to change(user.audits, :count).from(1).to(2)
|
|
503
|
+
expect(user.audits.last.action).to eq("update")
|
|
504
|
+
expect(user.audits.last.audited_changes.keys).to eq(%w[suspended_at])
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
context "after updating" do
|
|
509
|
+
it "changing nested resource shouldn't audit owner" do
|
|
510
|
+
expect { user.update(username: "test") }.to change(user.audits, :count).from(1).to(2)
|
|
511
|
+
expect { company.update(type: "test") }.not_to change(user.audits, :count)
|
|
512
|
+
|
|
513
|
+
expect { user.touch(:suspended_at) }.to change(user.audits, :count).from(2).to(3)
|
|
514
|
+
expect { company.update(type: "another_test") }.not_to change(user.audits, :count)
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
|
|
417
521
|
describe "on destroy" do
|
|
418
522
|
before do
|
|
419
523
|
@user = create_user(status: :active)
|
data/spec/audited_spec.rb
CHANGED
|
@@ -3,16 +3,12 @@ require "spec_helper"
|
|
|
3
3
|
describe Audited do
|
|
4
4
|
describe "#store" do
|
|
5
5
|
describe "maintains state of store" do
|
|
6
|
-
let(:current_user) {
|
|
6
|
+
let(:current_user) { RequestStore.store[:audited_store] }
|
|
7
7
|
before { Audited.store[:current_user] = current_user }
|
|
8
8
|
|
|
9
|
-
it "
|
|
9
|
+
it "checks store is not nil" do
|
|
10
10
|
expect(Audited.store[:current_user]).to eq(current_user)
|
|
11
11
|
end
|
|
12
|
-
|
|
13
|
-
it "when executed with Fibers" do
|
|
14
|
-
Fiber.new { expect(Audited.store[:current_user]).to eq(current_user) }.resume
|
|
15
|
-
end
|
|
16
12
|
end
|
|
17
13
|
end
|
|
18
14
|
end
|
|
@@ -5,11 +5,34 @@ module RailsApp
|
|
|
5
5
|
config.root = File.expand_path("../../", __FILE__)
|
|
6
6
|
config.i18n.enforce_available_locales = true
|
|
7
7
|
|
|
8
|
-
if
|
|
8
|
+
if Rails.version.start_with?("7.1") && config.active_record.respond_to?(:yaml_column_permitted_classes=)
|
|
9
|
+
config.active_record.yaml_column_permitted_classes = [
|
|
10
|
+
String,
|
|
11
|
+
Symbol,
|
|
12
|
+
Integer,
|
|
13
|
+
NilClass,
|
|
14
|
+
Float,
|
|
15
|
+
Time,
|
|
16
|
+
Date,
|
|
17
|
+
FalseClass,
|
|
18
|
+
Hash,
|
|
19
|
+
Array,
|
|
20
|
+
DateTime,
|
|
21
|
+
TrueClass,
|
|
22
|
+
BigDecimal,
|
|
23
|
+
ActiveSupport::TimeWithZone,
|
|
24
|
+
ActiveSupport::TimeZone,
|
|
25
|
+
ActiveSupport::HashWithIndifferentAccess
|
|
26
|
+
]
|
|
27
|
+
elsif !Rails.version.start_with?("5.0") && !Rails.version.start_with?("5.1") && config.active_record.respond_to?(:yaml_column_permitted_classes=)
|
|
9
28
|
config.active_record.yaml_column_permitted_classes =
|
|
10
29
|
%w[String Symbol Integer NilClass Float Time Date FalseClass Hash Array DateTime TrueClass BigDecimal
|
|
11
30
|
ActiveSupport::TimeWithZone ActiveSupport::TimeZone ActiveSupport::HashWithIndifferentAccess]
|
|
12
31
|
end
|
|
32
|
+
|
|
33
|
+
if Rails.version >= "7.1"
|
|
34
|
+
config.active_support.cache_format_version = 7.1
|
|
35
|
+
end
|
|
13
36
|
end
|
|
14
37
|
end
|
|
15
38
|
|
|
@@ -8,7 +8,12 @@ module Models
|
|
|
8
8
|
attribute :non_column_attr if Rails.version >= "5.1"
|
|
9
9
|
attr_protected :logins if respond_to?(:attr_protected)
|
|
10
10
|
enum status: {active: 0, reliable: 1, banned: 2}
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
if Rails.version >= "7.1"
|
|
13
|
+
serialize :phone_numbers, type: Array
|
|
14
|
+
else
|
|
15
|
+
serialize :phone_numbers, Array
|
|
16
|
+
end
|
|
12
17
|
|
|
13
18
|
def name=(val)
|
|
14
19
|
write_attribute(:name, CGI.escapeHTML(val))
|
|
@@ -124,11 +129,12 @@ module Models
|
|
|
124
129
|
audited
|
|
125
130
|
has_associated_audits
|
|
126
131
|
has_many :companies, class_name: "OwnedCompany", dependent: :destroy
|
|
132
|
+
accepts_nested_attributes_for :companies
|
|
127
133
|
end
|
|
128
134
|
|
|
129
135
|
class OwnedCompany < ::ActiveRecord::Base
|
|
130
136
|
self.table_name = "companies"
|
|
131
|
-
belongs_to :owner, class_name: "Owner"
|
|
137
|
+
belongs_to :owner, class_name: "Owner", touch: true
|
|
132
138
|
attr_accessible :name, :owner if respond_to?(:attr_accessible) # declare attr_accessible before calling aaa
|
|
133
139
|
audited associated_with: :owner
|
|
134
140
|
end
|
|
@@ -146,6 +152,11 @@ module Models
|
|
|
146
152
|
audited on: [:create, :destroy]
|
|
147
153
|
end
|
|
148
154
|
|
|
155
|
+
class OnCreateDestroyUser < ::ActiveRecord::Base
|
|
156
|
+
self.table_name = "users"
|
|
157
|
+
audited on: [:create, :destroy]
|
|
158
|
+
end
|
|
159
|
+
|
|
149
160
|
class OnCreateDestroyExceptName < ::ActiveRecord::Base
|
|
150
161
|
self.table_name = "companies"
|
|
151
162
|
audited except: :name, on: [:create, :destroy]
|
|
@@ -155,5 +166,10 @@ module Models
|
|
|
155
166
|
self.table_name = "companies"
|
|
156
167
|
audited on: [:create, :update]
|
|
157
168
|
end
|
|
169
|
+
|
|
170
|
+
class OnTouchOnly < ::ActiveRecord::Base
|
|
171
|
+
self.table_name = "users"
|
|
172
|
+
audited on: [:touch]
|
|
173
|
+
end
|
|
158
174
|
end
|
|
159
175
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: audited
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brandon Keepers
|
|
@@ -13,7 +13,7 @@ authors:
|
|
|
13
13
|
autorequire:
|
|
14
14
|
bindir: bin
|
|
15
15
|
cert_chain: []
|
|
16
|
-
date: 2023-
|
|
16
|
+
date: 2023-09-30 00:00:00.000000000 Z
|
|
17
17
|
dependencies:
|
|
18
18
|
- !ruby/object:Gem::Dependency
|
|
19
19
|
name: activerecord
|
|
@@ -24,7 +24,7 @@ dependencies:
|
|
|
24
24
|
version: '5.0'
|
|
25
25
|
- - "<"
|
|
26
26
|
- !ruby/object:Gem::Version
|
|
27
|
-
version: '7.
|
|
27
|
+
version: '7.2'
|
|
28
28
|
type: :runtime
|
|
29
29
|
prerelease: false
|
|
30
30
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -34,7 +34,21 @@ dependencies:
|
|
|
34
34
|
version: '5.0'
|
|
35
35
|
- - "<"
|
|
36
36
|
- !ruby/object:Gem::Version
|
|
37
|
-
version: '7.
|
|
37
|
+
version: '7.2'
|
|
38
|
+
- !ruby/object:Gem::Dependency
|
|
39
|
+
name: request_store
|
|
40
|
+
requirement: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - "~>"
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: '1.2'
|
|
45
|
+
type: :runtime
|
|
46
|
+
prerelease: false
|
|
47
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - "~>"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '1.2'
|
|
38
52
|
- !ruby/object:Gem::Dependency
|
|
39
53
|
name: appraisal
|
|
40
54
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -182,6 +196,7 @@ files:
|
|
|
182
196
|
- gemfiles/rails60.gemfile
|
|
183
197
|
- gemfiles/rails61.gemfile
|
|
184
198
|
- gemfiles/rails70.gemfile
|
|
199
|
+
- gemfiles/rails71.gemfile
|
|
185
200
|
- lib/audited-rspec.rb
|
|
186
201
|
- lib/audited.rb
|
|
187
202
|
- lib/audited/audit.rb
|
|
@@ -252,7 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
252
267
|
- !ruby/object:Gem::Version
|
|
253
268
|
version: '0'
|
|
254
269
|
requirements: []
|
|
255
|
-
rubygems_version: 3.
|
|
270
|
+
rubygems_version: 3.4.7
|
|
256
271
|
signing_key:
|
|
257
272
|
specification_version: 4
|
|
258
273
|
summary: Log all changes to your models
|