audited 4.10.0 → 5.0.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 +4 -4
- data/.standard.yml +5 -0
- data/.travis.yml +25 -21
- data/Appraisals +10 -18
- data/CHANGELOG.md +29 -1
- data/Gemfile +1 -1
- data/README.md +16 -3
- data/Rakefile +6 -6
- data/lib/audited-rspec.rb +3 -1
- data/lib/audited.rb +25 -8
- data/lib/audited/audit.rb +24 -25
- data/lib/audited/auditor.rb +45 -39
- 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/generators/audited/install_generator.rb +9 -7
- data/lib/generators/audited/migration.rb +2 -0
- 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 +67 -45
- data/spec/audited/auditor_spec.rb +284 -253
- data/spec/audited/sweeper_spec.rb +19 -19
- data/spec/audited_spec.rb +18 -0
- data/spec/audited_spec_helpers.rb +5 -7
- data/spec/rails_app/app/assets/config/manifest.js +2 -1
- data/spec/rails_app/config/application.rb +3 -3
- data/spec/rails_app/config/environment.rb +1 -1
- data/spec/rails_app/config/environments/test.rb +5 -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 +16 -12
- 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 +25 -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 +20 -22
- data/.rubocop.yml +0 -25
- 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
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Audited
|
4
|
+
class Railtie < Rails::Railtie
|
5
|
+
initializer "audited.sweeper" do
|
6
|
+
ActiveSupport.on_load(:action_controller) do
|
7
|
+
if defined?(ActionController::Base)
|
8
|
+
ActionController::Base.around_action Audited::Sweeper.new
|
9
|
+
end
|
10
|
+
if defined?(ActionController::API)
|
11
|
+
ActionController::API.around_action Audited::Sweeper.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Audited
|
2
4
|
module RspecMatchers
|
3
5
|
# Ensure that the model is audited.
|
@@ -78,9 +80,9 @@ module Audited
|
|
78
80
|
def description
|
79
81
|
description = "audited"
|
80
82
|
description += " associated with #{@options[:associated_with]}" if @options.key?(:associated_with)
|
81
|
-
description += " only => #{@options[:only].join
|
82
|
-
description += " except => #{@options[:except].join(
|
83
|
-
description += " requires audit_comment"
|
83
|
+
description += " only => #{@options[:only].join ", "}" if @options.key?(:only)
|
84
|
+
description += " except => #{@options[:except].join(", ")}" if @options.key?(:except)
|
85
|
+
description += " requires audit_comment" if @options.key?(:comment_required)
|
84
86
|
|
85
87
|
description
|
86
88
|
end
|
data/lib/audited/sweeper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Audited
|
2
4
|
class Sweeper
|
3
5
|
STORED_DATA = {
|
@@ -10,7 +12,7 @@ module Audited
|
|
10
12
|
|
11
13
|
def around(controller)
|
12
14
|
self.controller = controller
|
13
|
-
STORED_DATA.each { |k,m| store[k] = send(m) }
|
15
|
+
STORED_DATA.each { |k, m| store[k] = send(m) }
|
14
16
|
yield
|
15
17
|
ensure
|
16
18
|
self.controller = nil
|
@@ -38,12 +40,3 @@ module Audited
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
41
|
-
|
42
|
-
ActiveSupport.on_load(:action_controller) do
|
43
|
-
if defined?(ActionController::Base)
|
44
|
-
ActionController::Base.around_action Audited::Sweeper.new
|
45
|
-
end
|
46
|
-
if defined?(ActionController::API)
|
47
|
-
ActionController::API.around_action Audited::Sweeper.new
|
48
|
-
end
|
49
|
-
end
|
data/lib/audited/version.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
require "rails/generators/migration"
|
5
|
+
require "active_record"
|
6
|
+
require "rails/generators/active_record"
|
7
|
+
require "generators/audited/migration"
|
8
|
+
require "generators/audited/migration_helper"
|
7
9
|
|
8
10
|
module Audited
|
9
11
|
module Generators
|
@@ -18,7 +20,7 @@ module Audited
|
|
18
20
|
source_root File.expand_path("../templates", __FILE__)
|
19
21
|
|
20
22
|
def copy_migration
|
21
|
-
migration_template
|
23
|
+
migration_template "install.rb", "db/migrate/install_audited.rb"
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Audited
|
2
4
|
module Generators
|
3
5
|
module MigrationHelper
|
4
6
|
def migration_parent
|
5
|
-
|
7
|
+
"ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
|
6
8
|
end
|
7
9
|
end
|
8
10
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
require "rails/generators/migration"
|
5
|
+
require "active_record"
|
6
|
+
require "rails/generators/active_record"
|
7
|
+
require "generators/audited/migration"
|
8
|
+
require "generators/audited/migration_helper"
|
7
9
|
|
8
10
|
module Audited
|
9
11
|
module Generators
|
@@ -27,31 +29,31 @@ module Audited
|
|
27
29
|
columns = Audited::Audit.columns.map(&:name)
|
28
30
|
indexes = Audited::Audit.connection.indexes(Audited::Audit.table_name)
|
29
31
|
|
30
|
-
yield :add_comment_to_audits unless columns.include?(
|
32
|
+
yield :add_comment_to_audits unless columns.include?("comment")
|
31
33
|
|
32
|
-
if columns.include?(
|
34
|
+
if columns.include?("changes")
|
33
35
|
yield :rename_changes_to_audited_changes
|
34
36
|
end
|
35
37
|
|
36
|
-
unless columns.include?(
|
38
|
+
unless columns.include?("remote_address")
|
37
39
|
yield :add_remote_address_to_audits
|
38
40
|
end
|
39
41
|
|
40
|
-
unless columns.include?(
|
42
|
+
unless columns.include?("request_uuid")
|
41
43
|
yield :add_request_uuid_to_audits
|
42
44
|
end
|
43
45
|
|
44
|
-
unless columns.include?(
|
45
|
-
if columns.include?(
|
46
|
+
unless columns.include?("association_id")
|
47
|
+
if columns.include?("auditable_parent_id")
|
46
48
|
yield :rename_parent_to_association
|
47
49
|
else
|
48
|
-
unless columns.include?(
|
50
|
+
unless columns.include?("associated_id")
|
49
51
|
yield :add_association_to_audits
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
54
|
-
if columns.include?(
|
56
|
+
if columns.include?("association_id")
|
55
57
|
yield :rename_association_to_associated
|
56
58
|
end
|
57
59
|
|
data/spec/audited/audit_spec.rb
CHANGED
@@ -2,6 +2,27 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
SingleCov.covered! uncovered: 1 # Rails version check
|
4
4
|
|
5
|
+
class CustomAudit < Audited::Audit
|
6
|
+
def custom_method
|
7
|
+
"I'm custom!"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class TempModel1 < ::ActiveRecord::Base
|
12
|
+
self.table_name = :companies
|
13
|
+
end
|
14
|
+
|
15
|
+
class TempModel2 < ::ActiveRecord::Base
|
16
|
+
self.table_name = :companies
|
17
|
+
end
|
18
|
+
|
19
|
+
class Models::ActiveRecord::CustomUser < ::ActiveRecord::Base
|
20
|
+
end
|
21
|
+
|
22
|
+
class Models::ActiveRecord::CustomUserSubclass < Models::ActiveRecord::CustomUser
|
23
|
+
audited
|
24
|
+
end
|
25
|
+
|
5
26
|
describe Audited::Audit do
|
6
27
|
let(:user) { Models::ActiveRecord::User.new name: "Testing" }
|
7
28
|
|
@@ -9,30 +30,17 @@ describe Audited::Audit do
|
|
9
30
|
around(:example) do |example|
|
10
31
|
original_audit_class = Audited.audit_class
|
11
32
|
|
12
|
-
class CustomAudit < Audited::Audit
|
13
|
-
def custom_method
|
14
|
-
"I'm custom!"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class TempModel < ::ActiveRecord::Base
|
19
|
-
self.table_name = :companies
|
20
|
-
end
|
21
|
-
|
22
33
|
example.run
|
23
34
|
|
24
35
|
Audited.config { |config| config.audit_class = original_audit_class }
|
25
|
-
Audited::Audit.audited_class_names.delete("TempModel")
|
26
|
-
Object.send(:remove_const, :TempModel)
|
27
|
-
Object.send(:remove_const, :CustomAudit)
|
28
36
|
end
|
29
37
|
|
30
38
|
context "when a custom audit class is configured" do
|
31
39
|
it "should be used in place of #{described_class}" do
|
32
40
|
Audited.config { |config| config.audit_class = CustomAudit }
|
33
|
-
|
41
|
+
TempModel1.audited
|
34
42
|
|
35
|
-
record =
|
43
|
+
record = TempModel1.create
|
36
44
|
|
37
45
|
audit = record.audits.first
|
38
46
|
expect(audit).to be_a CustomAudit
|
@@ -42,9 +50,9 @@ describe Audited::Audit do
|
|
42
50
|
|
43
51
|
context "when a custom audit class is not configured" do
|
44
52
|
it "should default to #{described_class}" do
|
45
|
-
|
53
|
+
TempModel2.audited
|
46
54
|
|
47
|
-
record =
|
55
|
+
record = TempModel2.create
|
48
56
|
|
49
57
|
audit = record.audits.first
|
50
58
|
expect(audit).to be_a Audited::Audit
|
@@ -72,7 +80,7 @@ describe Audited::Audit do
|
|
72
80
|
let(:user) { Models::ActiveRecord::User.create(name: "John") }
|
73
81
|
|
74
82
|
it "undos changes" do
|
75
|
-
user.update_attribute(:name,
|
83
|
+
user.update_attribute(:name, "Joe")
|
76
84
|
user.audits.last.undo
|
77
85
|
user.reload
|
78
86
|
expect(user.name).to eq("John")
|
@@ -87,12 +95,12 @@ describe Audited::Audit do
|
|
87
95
|
|
88
96
|
it "undos creation" do
|
89
97
|
user # trigger create
|
90
|
-
expect {user.audits.last.undo}.to change(Models::ActiveRecord::User, :count).by(-1)
|
98
|
+
expect { user.audits.last.undo }.to change(Models::ActiveRecord::User, :count).by(-1)
|
91
99
|
end
|
92
100
|
|
93
101
|
it "fails when trying to undo unknown" do
|
94
102
|
audit = user.audits.last
|
95
|
-
audit.action =
|
103
|
+
audit.action = "oops"
|
96
104
|
expect { audit.undo }.to raise_error("invalid action given oops")
|
97
105
|
end
|
98
106
|
end
|
@@ -105,8 +113,8 @@ describe Audited::Audit do
|
|
105
113
|
|
106
114
|
it "should be able to set the user to nil" do
|
107
115
|
subject.user_id = 1
|
108
|
-
subject.user_type =
|
109
|
-
subject.username =
|
116
|
+
subject.user_type = "Models::ActiveRecord::User"
|
117
|
+
subject.username = "joe"
|
110
118
|
|
111
119
|
subject.user = nil
|
112
120
|
|
@@ -117,19 +125,19 @@ describe Audited::Audit do
|
|
117
125
|
end
|
118
126
|
|
119
127
|
it "should be able to set the user to a string" do
|
120
|
-
subject.user =
|
121
|
-
expect(subject.user).to eq(
|
128
|
+
subject.user = "test"
|
129
|
+
expect(subject.user).to eq("test")
|
122
130
|
end
|
123
131
|
|
124
132
|
it "should clear model when setting to a string" do
|
125
133
|
subject.user = user
|
126
|
-
subject.user =
|
134
|
+
subject.user = "testing"
|
127
135
|
expect(subject.user_id).to be_nil
|
128
136
|
expect(subject.user_type).to be_nil
|
129
137
|
end
|
130
138
|
|
131
139
|
it "should clear the username when setting to a model" do
|
132
|
-
subject.username =
|
140
|
+
subject.username = "test"
|
133
141
|
subject.user = user
|
134
142
|
expect(subject.username).to be_nil
|
135
143
|
end
|
@@ -138,7 +146,7 @@ describe Audited::Audit do
|
|
138
146
|
describe "revision" do
|
139
147
|
it "should recreate attributes" do
|
140
148
|
user = Models::ActiveRecord::User.create name: "1"
|
141
|
-
5.times {|i| user.update_attribute :name, (i + 2).to_s }
|
149
|
+
5.times { |i| user.update_attribute :name, (i + 2).to_s }
|
142
150
|
|
143
151
|
user.audits.each do |audit|
|
144
152
|
expect(audit.revision.name).to eq(audit.version.to_s)
|
@@ -174,7 +182,7 @@ describe Audited::Audit do
|
|
174
182
|
it "uses created at" do
|
175
183
|
Audited::Audit.delete_all
|
176
184
|
audit = Models::ActiveRecord::User.create(name: "John").audits.last
|
177
|
-
audit.update_columns(created_at: Time.zone.parse(
|
185
|
+
audit.update_columns(created_at: Time.zone.parse("2018-01-01"))
|
178
186
|
expect(Audited::Audit.collection_cache_key).to match(/-20180101\d+$/)
|
179
187
|
end
|
180
188
|
else
|
@@ -220,12 +228,6 @@ describe Audited::Audit do
|
|
220
228
|
end
|
221
229
|
|
222
230
|
describe "audited_classes" do
|
223
|
-
class Models::ActiveRecord::CustomUser < ::ActiveRecord::Base
|
224
|
-
end
|
225
|
-
class Models::ActiveRecord::CustomUserSubclass < Models::ActiveRecord::CustomUser
|
226
|
-
audited
|
227
|
-
end
|
228
|
-
|
229
231
|
it "should include audited classes" do
|
230
232
|
expect(Audited::Audit.audited_classes).to include(Models::ActiveRecord::User)
|
231
233
|
end
|
@@ -236,17 +238,37 @@ describe Audited::Audit do
|
|
236
238
|
end
|
237
239
|
|
238
240
|
describe "new_attributes" do
|
239
|
-
it "should return
|
240
|
-
new_attributes = Audited::Audit.new(audited_changes: {
|
241
|
+
it "should return the audited_changes without modification for create" do
|
242
|
+
new_attributes = Audited::Audit.new(audited_changes: {int: 1, array: [1]}, action: :create).new_attributes
|
243
|
+
expect(new_attributes).to eq({"int" => 1, "array" => [1]})
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should return a hash that contains the after values of each attribute" do
|
247
|
+
new_attributes = Audited::Audit.new(audited_changes: {a: [1, 2], b: [3, 4]}, action: :update).new_attributes
|
241
248
|
expect(new_attributes).to eq({"a" => 2, "b" => 4})
|
242
249
|
end
|
250
|
+
|
251
|
+
it "should return the audited_changes without modification for destroy" do
|
252
|
+
new_attributes = Audited::Audit.new(audited_changes: {int: 1, array: [1]}, action: :destroy).new_attributes
|
253
|
+
expect(new_attributes).to eq({"int" => 1, "array" => [1]})
|
254
|
+
end
|
243
255
|
end
|
244
256
|
|
245
257
|
describe "old_attributes" do
|
246
|
-
it "should return
|
247
|
-
old_attributes = Audited::Audit.new(audited_changes: {
|
258
|
+
it "should return the audited_changes without modification for create" do
|
259
|
+
old_attributes = Audited::Audit.new(audited_changes: {int: 1, array: [1]}, action: :create).new_attributes
|
260
|
+
expect(old_attributes).to eq({"int" => 1, "array" => [1]})
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should return a hash that contains the before values of each attribute" do
|
264
|
+
old_attributes = Audited::Audit.new(audited_changes: {a: [1, 2], b: [3, 4]}, action: :update).old_attributes
|
248
265
|
expect(old_attributes).to eq({"a" => 1, "b" => 3})
|
249
266
|
end
|
267
|
+
|
268
|
+
it "should return the audited_changes without modification for destroy" do
|
269
|
+
old_attributes = Audited::Audit.new(audited_changes: {int: 1, array: [1]}, action: :destroy).old_attributes
|
270
|
+
expect(old_attributes).to eq({"int" => 1, "array" => [1]})
|
271
|
+
end
|
250
272
|
end
|
251
273
|
|
252
274
|
describe "as_user" do
|
@@ -293,8 +315,8 @@ describe Audited::Audit do
|
|
293
315
|
end
|
294
316
|
end
|
295
317
|
|
296
|
-
|
297
|
-
|
318
|
+
if ActiveRecord::Base.connection.adapter_name != "SQLite"
|
319
|
+
it "should be thread safe" do
|
298
320
|
expect(user.save).to eq(true)
|
299
321
|
|
300
322
|
t1 = Thread.new do
|
@@ -314,10 +336,10 @@ describe Audited::Audit do
|
|
314
336
|
t1.join
|
315
337
|
t2.join
|
316
338
|
end
|
317
|
-
end
|
339
|
+
end
|
318
340
|
|
319
341
|
it "should return the value from the yield block" do
|
320
|
-
result = Audited::Audit.as_user(
|
342
|
+
result = Audited::Audit.as_user("foo") do
|
321
343
|
42
|
322
344
|
end
|
323
345
|
expect(result).to eq(42)
|
@@ -325,10 +347,10 @@ describe Audited::Audit do
|
|
325
347
|
|
326
348
|
it "should reset audited_user when the yield block raises an exception" do
|
327
349
|
expect {
|
328
|
-
Audited::Audit.as_user(
|
329
|
-
raise StandardError.new(
|
350
|
+
Audited::Audit.as_user("foo") do
|
351
|
+
raise StandardError.new("expected")
|
330
352
|
end
|
331
|
-
}.to raise_exception(
|
353
|
+
}.to raise_exception("expected")
|
332
354
|
expect(Audited.store[:audited_user]).to be_nil
|
333
355
|
end
|
334
356
|
end
|