audited 5.0.2 → 5.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bb58e8eb5b0de02a18ac5d089ccade2913c399ec66bcbf97551fd9a9f4afb6b
4
- data.tar.gz: 905621826a752e1796e0b81a7b448eec483e0ef27ce5de9f02845e0f5fd8be87
3
+ metadata.gz: e18ef251e91f3a66070afa58f5d9e5f12ac81777ca5389b3939a9fd349602e92
4
+ data.tar.gz: c0fbd5a136b6e43ae6e39229de6690811d24adf4f1f2f555a49752cac3bd230b
5
5
  SHA512:
6
- metadata.gz: 62448f486877e8a6c86505a7e5f53b805bf4f3a14cad907f83e69cd5175f43a4c3083a08ab4342bad18f5b8b1b104aa20d2d3c375ff86b7e60d48db9cbe00346
7
- data.tar.gz: 4bf37e3891074e6f329961c796db27191ead60d225860d3150f310a3888ed3ab52eab1564398ce2f26ad470ba2872979dd14ee48cddf0baaa8f7cbfb63c19091
6
+ metadata.gz: 9bbb38bc63b2cbafd43b7090ab307acde19e9ca21d22710ddc7b42a5a10fc08f0151c1b43b557a1978699005ac66ce7932eec7f8d5f3de6b3c14d7a4d77c73af
7
+ data.tar.gz: 707e5ddda189015b0475e663d7fb4faa3576a1a373dbe3f78436fce96e97cb7ed0a852fc328cec177716f95e035a45dd291f70888ba783572e4b854a84721a45
@@ -12,7 +12,7 @@ jobs:
12
12
  strategy:
13
13
  fail-fast: false
14
14
  matrix:
15
- ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0]
15
+ ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1]
16
16
  appraisal:
17
17
  - rails50
18
18
  - rails51
@@ -27,6 +27,11 @@ jobs:
27
27
  - ruby: 2.3
28
28
  db: MYSQL
29
29
 
30
+ # PostgresSQL is segfaulting on 2.3
31
+ # Doesn't seem worth solving.
32
+ - ruby: 2.3
33
+ db: POSTGRES
34
+
30
35
  # Rails 5.0 supports Ruby 2.2-2.4
31
36
  - appraisal: rails50
32
37
  ruby: 2.5
@@ -36,6 +41,8 @@ jobs:
36
41
  ruby: 2.7
37
42
  - appraisal: rails50
38
43
  ruby: 3.0
44
+ - appraisal: rails50
45
+ ruby: 3.1
39
46
 
40
47
  # Rails 5.1 supports Ruby 2.2-2.5
41
48
  - appraisal: rails51
@@ -44,6 +51,8 @@ jobs:
44
51
  ruby: 2.7
45
52
  - appraisal: rails51
46
53
  ruby: 3.0
54
+ - appraisal: rails51
55
+ ruby: 3.1
47
56
 
48
57
  # Rails 5.2 supports Ruby 2.2-2.5
49
58
  - appraisal: rails52
@@ -52,6 +61,8 @@ jobs:
52
61
  ruby: 2.7
53
62
  - appraisal: rails52
54
63
  ruby: 3.0
64
+ - appraisal: rails52
65
+ ruby: 3.1
55
66
 
56
67
  # Rails 6.0 supports Ruby 2.5-2.7
57
68
  - appraisal: rails60
@@ -60,6 +71,8 @@ jobs:
60
71
  ruby: 2.4
61
72
  - appraisal: rails60
62
73
  ruby: 3.0
74
+ - appraisal: rails60
75
+ ruby: 3.1
63
76
 
64
77
  # Rails 6.1 supports Ruby 2.5+
65
78
  - appraisal: rails61
@@ -101,7 +114,7 @@ jobs:
101
114
  sudo /etc/init.d/mysql start
102
115
  mysql -e 'CREATE DATABASE audited_test;' -uroot -proot
103
116
  mysql -e 'SHOW DATABASES;' -uroot -proot
104
- - uses: actions/checkout@v2
117
+ - uses: actions/checkout@v3
105
118
  - name: Copy Gemfile
106
119
  run: sed 's/\.\././' gemfiles/${{ matrix.appraisal }}.gemfile > Gemfile
107
120
  - name: Set up Ruby ${{ matrix.ruby }}
data/Appraisals CHANGED
@@ -6,6 +6,7 @@ appraise "rails50" do
6
6
  gem "mysql2", ">= 0.3.18", "< 0.6.0"
7
7
  gem "pg", ">= 0.18", "< 2.0"
8
8
  gem "sqlite3", "~> 1.3.6"
9
+ gem "psych", "~> 3.1"
9
10
  end
10
11
 
11
12
  appraise "rails51" do
@@ -13,13 +14,15 @@ appraise "rails51" do
13
14
  gem "mysql2", ">= 0.3.18", "< 0.6.0"
14
15
  gem "pg", ">= 0.18", "< 2.0"
15
16
  gem "sqlite3", "~> 1.3.6"
17
+ gem "psych", "~> 3.1"
16
18
  end
17
19
 
18
20
  appraise "rails52" do
19
- gem "rails", ">= 5.2.0", "< 5.3"
21
+ gem "rails", ">= 5.2.8.1", "< 5.3"
20
22
  gem "mysql2", ">= 0.4.4", "< 0.6.0"
21
23
  gem "pg", ">= 0.18", "< 2.0"
22
24
  gem "sqlite3", "~> 1.3.6"
25
+ gem "psych", "~> 3.1"
23
26
  end
24
27
 
25
28
  appraise "rails60" do
@@ -37,7 +40,7 @@ appraise "rails61" do
37
40
  end
38
41
 
39
42
  appraise "rails70" do
40
- gem "rails", ">= 7.0.0.alpha2", "< 7.1"
43
+ gem "rails", ">= 7.0.0", "< 7.1"
41
44
  gem "mysql2", ">= 0.4.4"
42
45
  gem "pg", ">= 1.1"
43
46
  gem "sqlite3", ">= 1.4"
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Audited ChangeLog
2
2
 
3
+ ## 5.1.0 (2022-12-23)
4
+
5
+ Changed
6
+
7
+ - config.audit_class takes a string - @simmerz
8
+ [#609](https://github.com/collectiveidea/audited/pull/609)
9
+ - Filter encrypted attributes automatically - @vlad-psh
10
+ [#630](https://github.com/collectiveidea/audited/pull/630)
11
+
12
+ Improved
13
+
14
+ - README improvements - @jess, @mstroming
15
+ [#605](https://github.com/collectiveidea/audited/pull/605)
16
+ [#640](https://github.com/collectiveidea/audited/issues/640)
17
+ - Ignore deadlocks in concurrent audit combinations - @Crammaman
18
+ [#621](https://github.com/collectiveidea/audited/pull/621)
19
+ - Fix timestamped_migrations deprecation warning - @shouichi
20
+ [#624](https://github.com/collectiveidea/audited/pull/624)
21
+ - Ensure audits are re-enabled after blocks - @dcorlett
22
+ [#632](https://github.com/collectiveidea/audited/pull/632)
23
+ - Replace raw string where clause with query methods - @macowie
24
+ [#642](https://github.com/collectiveidea/audited/pull/642)
25
+ - Test against more Ruby/Rails Versions - @enomotodev, @danielmorrison
26
+ [#610](https://github.com/collectiveidea/audited/pull/610)
27
+ [#643](https://github.com/collectiveidea/audited/pull/643)
28
+
3
29
  ## 5.0.2 (2021-09-16)
4
30
 
5
31
  Added
@@ -11,7 +37,7 @@ Improved
11
37
 
12
38
  - Improve loading - @mvastola
13
39
  [#592](https://github.com/collectiveidea/audited/pull/592)
14
- - Update README - @danirod, clement1234
40
+ - Update README - @danirod, @clement1234
15
41
  [#596](https://github.com/collectiveidea/audited/pull/596)
16
42
  [#594](https://github.com/collectiveidea/audited/pull/594)
17
43
 
data/README.md CHANGED
@@ -2,7 +2,6 @@ Audited
2
2
  [![Gem Version](https://img.shields.io/gem/v/audited.svg)](http://rubygems.org/gems/audited)
3
3
  ![Build Status](https://github.com/collectiveidea/audited/actions/workflows/ci.yml/badge.svg)
4
4
  [![Code Climate](https://codeclimate.com/github/collectiveidea/audited.svg)](https://codeclimate.com/github/collectiveidea/audited)
5
- [![Security](https://hakiri.io/github/collectiveidea/audited/master.svg)](https://hakiri.io/github/collectiveidea/audited/master)
6
5
  [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
7
6
  =======
8
7
 
@@ -18,12 +17,13 @@ For Rails 3, use gem version 3.0 or see the [3.0-stable branch](https://github.c
18
17
 
19
18
  Audited supports and is [tested against](https://github.com/collectiveidea/audited/actions/workflows/ci.yml) the following Ruby versions:
20
19
 
21
- * 2.3
20
+ * 2.3 (only tested on Sqlite due to testing issues with other DBs)
22
21
  * 2.4
23
22
  * 2.5
24
23
  * 2.6
25
24
  * 2.7
26
25
  * 3.0
26
+ * 3.1
27
27
 
28
28
  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
29
 
@@ -219,7 +219,7 @@ Audited.current_user_method = :authenticated_user
219
219
  Outside of a request, Audited can still record the user with the `as_user` method:
220
220
 
221
221
  ```ruby
222
- Audited.audit_class.as_user(User.find(1)) do
222
+ Audited.audit_model.as_user(User.find(1)) do
223
223
  post.update!(title: "Hello, world!")
224
224
  end
225
225
  post.audits.last.user # => #<User id: 1>
@@ -246,7 +246,7 @@ end
246
246
  `as_user` also accepts a string, which can be useful for auditing updates made in a CLI environment:
247
247
 
248
248
  ```rb
249
- Audited.audit_class.as_user("console-user-#{ENV['SSH_USER']}") do
249
+ Audited.audit_model.as_user("console-user-#{ENV['SSH_USER']}") do
250
250
  post.update_attributes!(title: "Hello, world!")
251
251
  end
252
252
  post.audits.last.user # => 'console-user-username'
@@ -286,6 +286,7 @@ class User < ActiveRecord::Base
286
286
  end
287
287
 
288
288
  class Company < ActiveRecord::Base
289
+ audited
289
290
  has_many :users
290
291
  has_associated_audits
291
292
  end
@@ -313,9 +314,7 @@ If you want to audit only under specific conditions, you can provide conditional
313
314
  ```ruby
314
315
  class User < ActiveRecord::Base
315
316
  audited if: :active?
316
-
317
- private
318
-
317
+
319
318
  def active?
320
319
  last_login > 6.months.ago
321
320
  end
@@ -386,6 +385,17 @@ User.auditing_enabled = false
386
385
  end
387
386
  ```
388
387
 
388
+ ### Encrypted attributes
389
+
390
+ If you're using ActiveRecord's encryption (available from Rails 7) to encrypt some attributes, Audited will automatically filter values of these attributes. No additional configuration is required. Changes to encrypted attributes will be logged as `[FILTERED]`.
391
+
392
+ ```ruby
393
+ class User < ActiveRecord::Base
394
+ audited
395
+ encrypts :password
396
+ end
397
+ ```
398
+
389
399
  ### Custom `Audit` model
390
400
 
391
401
  If you want to extend or modify the audit model, create a new class that
@@ -402,7 +412,7 @@ Then set it in an initializer:
402
412
  # config/initializers/audited.rb
403
413
 
404
414
  Audited.config do |config|
405
- config.audit_class = CustomAudit
415
+ config.audit_class = "CustomAudit"
406
416
  end
407
417
  ```
408
418
 
@@ -6,5 +6,6 @@ gem "rails", "~> 5.0.0"
6
6
  gem "mysql2", ">= 0.3.18", "< 0.6.0"
7
7
  gem "pg", ">= 0.18", "< 2.0"
8
8
  gem "sqlite3", "~> 1.3.6"
9
+ gem "psych", "~> 3.1"
9
10
 
10
11
  gemspec name: "audited", path: "../"
@@ -6,5 +6,6 @@ gem "rails", "~> 5.1.4"
6
6
  gem "mysql2", ">= 0.3.18", "< 0.6.0"
7
7
  gem "pg", ">= 0.18", "< 2.0"
8
8
  gem "sqlite3", "~> 1.3.6"
9
+ gem "psych", "~> 3.1"
9
10
 
10
11
  gemspec name: "audited", path: "../"
@@ -2,9 +2,10 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", ">= 5.2.0", "< 5.3"
5
+ gem "rails", ">= 5.2.8.1", "< 5.3"
6
6
  gem "mysql2", ">= 0.4.4", "< 0.6.0"
7
7
  gem "pg", ">= 0.18", "< 2.0"
8
8
  gem "sqlite3", "~> 1.3.6"
9
+ gem "psych", "~> 3.1"
9
10
 
10
11
  gemspec name: "audited", path: "../"
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", ">= 7.0.0.alpha2", "< 7.1"
5
+ gem "rails", ">= 7.0.0", "< 7.1"
6
6
  gem "mysql2", ">= 0.4.4"
7
7
  gem "pg", ">= 1.1"
8
8
  gem "sqlite3", ">= 1.4"
data/lib/audited/audit.rb CHANGED
@@ -34,7 +34,7 @@ module Audited
34
34
  end
35
35
 
36
36
  def text_column?
37
- Audited.audit_class.columns_hash["audited_changes"].type.to_s == "text"
37
+ Audited.audit_model.columns_hash["audited_changes"].type.to_s == "text"
38
38
  end
39
39
  end
40
40
  end
@@ -78,14 +78,14 @@ module Audited
78
78
  # Returns a hash of the changed attributes with the new values
79
79
  def new_attributes
80
80
  (audited_changes || {}).each_with_object({}.with_indifferent_access) do |(attr, values), attrs|
81
- attrs[attr] = (action == "update" ? values.last : values)
81
+ attrs[attr] = (action == "update") ? values.last : values
82
82
  end
83
83
  end
84
84
 
85
85
  # Returns a hash of the changed attributes with the old values
86
86
  def old_attributes
87
87
  (audited_changes || {}).each_with_object({}.with_indifferent_access) do |(attr, values), attrs|
88
- attrs[attr] = (action == "update" ? values.first : values)
88
+ attrs[attr] = (action == "update") ? values.first : values
89
89
  end
90
90
  end
91
91
 
@@ -174,7 +174,7 @@ module Audited
174
174
  if action == "create"
175
175
  self.version = 1
176
176
  else
177
- collection = Rails::VERSION::MAJOR >= 6 ? self.class.unscoped : self.class
177
+ collection = (Rails::VERSION::MAJOR >= 6) ? self.class.unscoped : self.class
178
178
  max = collection.auditable_finder(auditable_id, auditable_type).maximum(:version) || 0
179
179
  self.version = max + 1
180
180
  end
@@ -13,7 +13,7 @@ module Audited
13
13
  #
14
14
  # See <tt>Audited::Auditor::ClassMethods#audited</tt>
15
15
  # for configuration options
16
- module Auditor #:nodoc:
16
+ module Auditor # :nodoc:
17
17
  extend ActiveSupport::Concern
18
18
 
19
19
  CALLBACKS = [:audit_create, :audit_update, :audit_destroy]
@@ -79,8 +79,8 @@ module Audited
79
79
  before_destroy :require_comment if audited_options[:on].include?(:destroy)
80
80
  end
81
81
 
82
- has_many :audits, -> { order(version: :asc) }, as: :auditable, class_name: Audited.audit_class.name, inverse_of: :auditable
83
- Audited.audit_class.audited_class_names << to_s
82
+ has_many :audits, -> { order(version: :asc) }, as: :auditable, class_name: Audited.audit_class, inverse_of: :auditable
83
+ Audited.audit_model.audited_class_names << to_s
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)
@@ -97,7 +97,7 @@ module Audited
97
97
  end
98
98
 
99
99
  def has_associated_audits
100
- has_many :associated_audits, as: :associated, class_name: Audited.audit_class.name
100
+ has_many :associated_audits, as: :associated, class_name: Audited.audit_model.name
101
101
  end
102
102
  end
103
103
 
@@ -159,27 +159,28 @@ module Audited
159
159
  # Returns nil for versions greater than revisions count
160
160
  def revision(version)
161
161
  if version == :previous || audits.last.version >= version
162
- revision_with Audited.audit_class.reconstruct_attributes(audits_to(version))
162
+ revision_with Audited.audit_model.reconstruct_attributes(audits_to(version))
163
163
  end
164
164
  end
165
165
 
166
166
  # Find the oldest revision recorded prior to the date/time provided.
167
167
  def revision_at(date_or_time)
168
168
  audits = self.audits.up_until(date_or_time)
169
- revision_with Audited.audit_class.reconstruct_attributes(audits) unless audits.empty?
169
+ revision_with Audited.audit_model.reconstruct_attributes(audits) unless audits.empty?
170
170
  end
171
171
 
172
172
  # List of attributes that are audited.
173
173
  def audited_attributes
174
174
  audited_attributes = attributes.except(*self.class.non_audited_columns)
175
+ audited_attributes = redact_values(audited_attributes)
176
+ audited_attributes = filter_encrypted_attrs(audited_attributes)
175
177
  normalize_enum_changes(audited_attributes)
176
178
  end
177
179
 
178
180
  # Returns a list combined of record audits and associated audits.
179
181
  def own_and_associated_audits
180
- Audited.audit_class.unscoped
181
- .where("(auditable_type = :type AND auditable_id = :id) OR (associated_type = :type AND associated_id = :id)",
182
- type: self.class.base_class.name, id: id)
182
+ Audited.audit_model.unscoped.where(auditable: self)
183
+ .or(Audited.audit_model.unscoped.where(associated: self))
183
184
  .order(created_at: :desc)
184
185
  end
185
186
 
@@ -190,8 +191,13 @@ module Audited
190
191
  combine_target.comment = "#{combine_target.comment}\nThis audit is the result of multiple audits being combined."
191
192
 
192
193
  transaction do
193
- combine_target.save!
194
- audits_to_combine.unscope(:limit).where("version < ?", combine_target.version).delete_all
194
+ begin
195
+ combine_target.save!
196
+ audits_to_combine.unscope(:limit).where("version < ?", combine_target.version).delete_all
197
+ rescue ActiveRecord::Deadlocked
198
+ # Ignore Deadlocks, if the same record is getting its old audits combined more than once at the same time then
199
+ # both combining operations will be the same. Ignoring this error allows one of the combines to go through successfully.
200
+ end
195
201
  end
196
202
  end
197
203
 
@@ -206,7 +212,7 @@ module Audited
206
212
  revision.send :instance_variable_set, "@destroyed", false
207
213
  revision.send :instance_variable_set, "@_destroyed", false
208
214
  revision.send :instance_variable_set, "@marked_for_destruction", false
209
- Audited.audit_class.assign_revision_attributes(revision, attributes)
215
+ Audited.audit_model.assign_revision_attributes(revision, attributes)
210
216
 
211
217
  # Remove any association proxies so that they will be recreated
212
218
  # and reference the correct object for this revision. The only way
@@ -234,6 +240,7 @@ module Audited
234
240
  end
235
241
 
236
242
  filtered_changes = redact_values(filtered_changes)
243
+ filtered_changes = filter_encrypted_attrs(filtered_changes)
237
244
  filtered_changes = normalize_enum_changes(filtered_changes)
238
245
  filtered_changes.to_hash
239
246
  end
@@ -257,19 +264,36 @@ module Audited
257
264
  end
258
265
 
259
266
  def redact_values(filtered_changes)
260
- [audited_options[:redacted]].flatten.compact.each do |option|
261
- changes = filtered_changes[option.to_s]
262
- new_value = audited_options[:redaction_value] || REDACTED
263
- values = if changes.is_a? Array
264
- changes.map { new_value }
265
- else
266
- new_value
267
- end
268
- hash = {option.to_s => values}
269
- filtered_changes.merge!(hash)
267
+ filter_attr_values(
268
+ audited_changes: filtered_changes,
269
+ attrs: Array(audited_options[:redacted]).map(&:to_s),
270
+ placeholder: audited_options[:redaction_value] || REDACTED
271
+ )
272
+ end
273
+
274
+ def filter_encrypted_attrs(filtered_changes)
275
+ filter_attr_values(
276
+ audited_changes: filtered_changes,
277
+ attrs: respond_to?(:encrypted_attributes) ? Array(encrypted_attributes).map(&:to_s) : []
278
+ )
279
+ end
280
+
281
+ # Replace values for given attrs to a placeholder and return modified hash
282
+ #
283
+ # @param audited_changes [Hash] Hash of changes to be saved to audited version record
284
+ # @param attrs [Array<String>] Array of attrs, values of which will be replaced to placeholder value
285
+ # @param placeholder [String] Placeholder to replace original attr values
286
+ def filter_attr_values(audited_changes: {}, attrs: [], placeholder: "[FILTERED]")
287
+ attrs.each do |attr|
288
+ next unless audited_changes.key?(attr)
289
+
290
+ changes = audited_changes[attr]
291
+ values = changes.is_a?(Array) ? changes.map { placeholder } : placeholder
292
+
293
+ audited_changes[attr] = values
270
294
  end
271
295
 
272
- filtered_changes
296
+ audited_changes
273
297
  end
274
298
 
275
299
  def rails_below?(rails_version)
@@ -290,20 +314,20 @@ module Audited
290
314
 
291
315
  def audit_create
292
316
  write_audit(action: "create", audited_changes: audited_attributes,
293
- comment: audit_comment)
317
+ comment: audit_comment)
294
318
  end
295
319
 
296
320
  def audit_update
297
321
  unless (changes = audited_changes).empty? && (audit_comment.blank? || audited_options[:update_with_comment_only] == false)
298
322
  write_audit(action: "update", audited_changes: changes,
299
- comment: audit_comment)
323
+ comment: audit_comment)
300
324
  end
301
325
  end
302
326
 
303
327
  def audit_destroy
304
328
  unless new_record?
305
329
  write_audit(action: "destroy", audited_changes: audited_attributes,
306
- comment: audit_comment)
330
+ comment: audit_comment)
307
331
  end
308
332
  end
309
333
 
@@ -397,7 +421,7 @@ module Audited
397
421
  # end
398
422
  #
399
423
  def without_auditing
400
- auditing_was_enabled = auditing_enabled
424
+ auditing_was_enabled = class_auditing_enabled
401
425
  disable_auditing
402
426
  yield
403
427
  ensure
@@ -411,7 +435,7 @@ module Audited
411
435
  # end
412
436
  #
413
437
  def with_auditing
414
- auditing_was_enabled = auditing_enabled
438
+ auditing_was_enabled = class_auditing_enabled
415
439
  enable_auditing
416
440
  yield
417
441
  ensure
@@ -431,11 +455,11 @@ module Audited
431
455
  # convenience wrapper around
432
456
  # @see Audit#as_user.
433
457
  def audit_as(user, &block)
434
- Audited.audit_class.as_user(user, &block)
458
+ Audited.audit_model.as_user(user, &block)
435
459
  end
436
460
 
437
461
  def auditing_enabled
438
- Audited.store.fetch("#{table_name}_auditing_enabled", true) && Audited.auditing_enabled
462
+ class_auditing_enabled && Audited.auditing_enabled
439
463
  end
440
464
 
441
465
  def auditing_enabled=(val)
@@ -466,6 +490,10 @@ module Audited
466
490
  default_ignored_attributes
467
491
  end
468
492
  end
493
+
494
+ def class_auditing_enabled
495
+ Audited.store.fetch("#{table_name}_auditing_enabled", true)
496
+ end
469
497
  end
470
498
  end
471
499
  end
@@ -221,7 +221,7 @@ module Audited
221
221
  def association_exists?
222
222
  !reflection.nil? &&
223
223
  reflection.macro == :has_many &&
224
- reflection.options[:class_name] == Audited.audit_class.name
224
+ reflection.options[:class_name] == Audited.audit_model.name
225
225
  end
226
226
  end
227
227
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Audited
4
- VERSION = "5.0.2"
4
+ VERSION = "5.1.0"
5
5
  end
data/lib/audited.rb CHANGED
@@ -13,7 +13,11 @@ module Audited
13
13
  attr_writer :audit_class
14
14
 
15
15
  def audit_class
16
- @audit_class ||= Audit
16
+ @audit_class ||= "Audited::Audit"
17
+ end
18
+
19
+ def audit_model
20
+ audit_class.constantize
17
21
  end
18
22
 
19
23
  def store
@@ -4,14 +4,22 @@ module Audited
4
4
  module Generators
5
5
  module Migration
6
6
  # Implement the required interface for Rails::Generators::Migration.
7
- def next_migration_number(dirname) #:nodoc:
7
+ def next_migration_number(dirname) # :nodoc:
8
8
  next_migration_number = current_migration_number(dirname) + 1
9
- if ::ActiveRecord::Base.timestamped_migrations
9
+ if timestamped_migrations?
10
10
  [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
11
11
  else
12
12
  "%.3d" % next_migration_number
13
13
  end
14
14
  end
15
+
16
+ private
17
+
18
+ def timestamped_migrations?
19
+ (Rails.version >= "7.0") ?
20
+ ::ActiveRecord.timestamped_migrations :
21
+ ::ActiveRecord::Base.timestamped_migrations
22
+ end
15
23
  end
16
24
  end
17
25
  end
@@ -37,7 +37,7 @@ describe Audited::Audit do
37
37
 
38
38
  context "when a custom audit class is configured" do
39
39
  it "should be used in place of #{described_class}" do
40
- Audited.config { |config| config.audit_class = CustomAudit }
40
+ Audited.config { |config| config.audit_class = "CustomAudit" }
41
41
  TempModel1.audited
42
42
 
43
43
  record = TempModel1.create
@@ -62,7 +62,7 @@ describe Audited::Audit do
62
62
  end
63
63
 
64
64
  describe "#audited_changes" do
65
- let(:audit) { Audited.audit_class.new }
65
+ let(:audit) { Audited.audit_model.new }
66
66
 
67
67
  it "can unserialize yaml from text columns" do
68
68
  audit.audited_changes = {foo: "bar"}
@@ -234,6 +234,14 @@ describe Audited::Auditor do
234
234
  expect(user.audits.last.audited_changes["password"]).to eq(["My", "Custom", "Value", 7])
235
235
  end
236
236
 
237
+ if ::ActiveRecord::VERSION::MAJOR >= 7
238
+ it "should filter encrypted attributes" do
239
+ user = Models::ActiveRecord::UserWithEncryptedPassword.create(password: "password")
240
+ user.save
241
+ expect(user.audits.last.audited_changes["password"]).to eq("[FILTERED]")
242
+ end
243
+ end
244
+
237
245
  if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
238
246
  describe "'json' and 'jsonb' audited_changes column type" do
239
247
  let(:migrations_path) { SPEC_ROOT.join("support/active_record/postgres") }
@@ -272,11 +280,11 @@ describe Audited::Auditor do
272
280
  yesterday = 1.day.ago
273
281
 
274
282
  u = Models::ActiveRecord::NoAttributeProtectionUser.new(name: "name",
275
- username: "username",
276
- password: "password",
277
- activated: true,
278
- suspended_at: yesterday,
279
- logins: 2)
283
+ username: "username",
284
+ password: "password",
285
+ activated: true,
286
+ suspended_at: yesterday,
287
+ logins: 2)
280
288
 
281
289
  expect(u.name).to eq("name")
282
290
  expect(u.username).to eq("username")
@@ -814,6 +822,15 @@ describe Audited::Auditor do
814
822
  }.to_not change(Audited::Audit, :count)
815
823
  end
816
824
 
825
+ context "when global audits are disabled" do
826
+ it "should re-enable class audits after #without_auditing block" do
827
+ Audited.auditing_enabled = false
828
+ Models::ActiveRecord::User.without_auditing {}
829
+ Audited.auditing_enabled = true
830
+ expect(Models::ActiveRecord::User.auditing_enabled).to eql(true)
831
+ end
832
+ end
833
+
817
834
  it "should reset auditing status even it raises an exception" do
818
835
  begin
819
836
  Models::ActiveRecord::User.without_auditing { raise }
@@ -884,6 +901,15 @@ describe Audited::Auditor do
884
901
  }.to change(Audited::Audit, :count).by(1)
885
902
  end
886
903
 
904
+ context "when global audits are disabled" do
905
+ it "should re-enable class audits after #with_auditing block" do
906
+ Audited.auditing_enabled = false
907
+ Models::ActiveRecord::User.with_auditing {}
908
+ Audited.auditing_enabled = true
909
+ expect(Models::ActiveRecord::User.auditing_enabled).to eql(true)
910
+ end
911
+ end
912
+
887
913
  it "should reset auditing status even it raises an exception" do
888
914
  Models::ActiveRecord::User.disable_auditing
889
915
  begin
@@ -4,6 +4,12 @@ module RailsApp
4
4
  class Application < Rails::Application
5
5
  config.root = File.expand_path("../../", __FILE__)
6
6
  config.i18n.enforce_available_locales = true
7
+
8
+ if !Rails.version.start_with?("5.0") && !Rails.version.start_with?("5.1") && config.active_record.respond_to?(:yaml_column_permitted_classes=)
9
+ config.active_record.yaml_column_permitted_classes =
10
+ %w[String Symbol Integer NilClass Float Time Date FalseClass Hash Array DateTime TrueClass BigDecimal
11
+ ActiveSupport::TimeWithZone ActiveSupport::TimeZone ActiveSupport::HashWithIndifferentAccess]
12
+ end
7
13
  end
8
14
  end
9
15
 
@@ -44,4 +44,9 @@ RailsApp::Application.configure do
44
44
 
45
45
  # Raises error for missing translations
46
46
  # config.action_view.raise_on_missing_translations = true
47
+
48
+ if ::ActiveRecord::VERSION::MAJOR >= 7
49
+ config.active_record.encryption.key_derivation_salt = SecureRandom.hex
50
+ config.active_record.encryption.primary_key = SecureRandom.hex
51
+ end
47
52
  end
@@ -41,6 +41,14 @@ module Models
41
41
  audited redacted: :password, redaction_value: ["My", "Custom", "Value", 7]
42
42
  end
43
43
 
44
+ if ::ActiveRecord::VERSION::MAJOR >= 7
45
+ class UserWithEncryptedPassword < ::ActiveRecord::Base
46
+ self.table_name = :users
47
+ audited
48
+ encrypts :password
49
+ end
50
+ end
51
+
44
52
  class CommentRequiredUser < ::ActiveRecord::Base
45
53
  self.table_name = :users
46
54
  audited except: :password, comment_required: true
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.0.2
4
+ version: 5.1.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: 2021-09-16 00:00:00.000000000 Z
16
+ date: 2022-12-23 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: activerecord
@@ -115,16 +115,16 @@ dependencies:
115
115
  name: sqlite3
116
116
  requirement: !ruby/object:Gem::Requirement
117
117
  requirements:
118
- - - "~>"
118
+ - - ">="
119
119
  - !ruby/object:Gem::Version
120
- version: '1.3'
120
+ version: 1.3.6
121
121
  type: :development
122
122
  prerelease: false
123
123
  version_requirements: !ruby/object:Gem::Requirement
124
124
  requirements:
125
- - - "~>"
125
+ - - ">="
126
126
  - !ruby/object:Gem::Version
127
- version: '1.3'
127
+ version: 1.3.6
128
128
  - !ruby/object:Gem::Dependency
129
129
  name: mysql2
130
130
  requirement: !ruby/object:Gem::Requirement
@@ -251,7 +251,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
251
251
  - !ruby/object:Gem::Version
252
252
  version: '0'
253
253
  requirements: []
254
- rubygems_version: 3.1.6
254
+ rubygems_version: 3.3.7
255
255
  signing_key:
256
256
  specification_version: 4
257
257
  summary: Log all changes to your models