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.

Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.standard.yml +5 -0
  3. data/.travis.yml +25 -21
  4. data/Appraisals +10 -18
  5. data/CHANGELOG.md +29 -1
  6. data/Gemfile +1 -1
  7. data/README.md +16 -3
  8. data/Rakefile +6 -6
  9. data/lib/audited-rspec.rb +3 -1
  10. data/lib/audited.rb +25 -8
  11. data/lib/audited/audit.rb +24 -25
  12. data/lib/audited/auditor.rb +45 -39
  13. data/lib/audited/railtie.rb +16 -0
  14. data/lib/audited/rspec_matchers.rb +5 -3
  15. data/lib/audited/sweeper.rb +3 -10
  16. data/lib/audited/version.rb +3 -1
  17. data/lib/generators/audited/install_generator.rb +9 -7
  18. data/lib/generators/audited/migration.rb +2 -0
  19. data/lib/generators/audited/migration_helper.rb +3 -1
  20. data/lib/generators/audited/templates/add_association_to_audits.rb +2 -0
  21. data/lib/generators/audited/templates/add_comment_to_audits.rb +2 -0
  22. data/lib/generators/audited/templates/add_remote_address_to_audits.rb +2 -0
  23. data/lib/generators/audited/templates/add_request_uuid_to_audits.rb +2 -0
  24. data/lib/generators/audited/templates/add_version_to_auditable_index.rb +2 -0
  25. data/lib/generators/audited/templates/install.rb +2 -0
  26. data/lib/generators/audited/templates/rename_association_to_associated.rb +2 -0
  27. data/lib/generators/audited/templates/rename_changes_to_audited_changes.rb +2 -0
  28. data/lib/generators/audited/templates/rename_parent_to_association.rb +2 -0
  29. data/lib/generators/audited/templates/revert_polymorphic_indexes_order.rb +2 -0
  30. data/lib/generators/audited/upgrade_generator.rb +16 -14
  31. data/spec/audited/audit_spec.rb +67 -45
  32. data/spec/audited/auditor_spec.rb +284 -253
  33. data/spec/audited/sweeper_spec.rb +19 -19
  34. data/spec/audited_spec.rb +18 -0
  35. data/spec/audited_spec_helpers.rb +5 -7
  36. data/spec/rails_app/app/assets/config/manifest.js +2 -1
  37. data/spec/rails_app/config/application.rb +3 -3
  38. data/spec/rails_app/config/environment.rb +1 -1
  39. data/spec/rails_app/config/environments/test.rb +5 -5
  40. data/spec/rails_app/config/initializers/secret_token.rb +2 -2
  41. data/spec/spec_helper.rb +14 -14
  42. data/spec/support/active_record/models.rb +16 -12
  43. data/spec/support/active_record/postgres/1_change_audited_changes_type_to_json.rb +1 -2
  44. data/spec/support/active_record/postgres/2_change_audited_changes_type_to_jsonb.rb +1 -2
  45. data/spec/support/active_record/schema.rb +25 -19
  46. data/test/db/version_1.rb +2 -2
  47. data/test/db/version_2.rb +2 -2
  48. data/test/db/version_3.rb +2 -3
  49. data/test/db/version_4.rb +2 -3
  50. data/test/db/version_5.rb +0 -1
  51. data/test/db/version_6.rb +1 -1
  52. data/test/install_generator_test.rb +18 -19
  53. data/test/test_helper.rb +5 -5
  54. data/test/upgrade_generator_test.rb +13 -18
  55. metadata +20 -22
  56. data/.rubocop.yml +0 -25
  57. data/gemfiles/rails42.gemfile +0 -11
  58. data/spec/rails_app/app/controllers/application_controller.rb +0 -2
  59. data/spec/rails_app/config/environments/development.rb +0 -21
  60. 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 ', '}" if @options.key?(:only)
82
- description += " except => #{@options[:except].join(', ')}" if @options.key?(:except)
83
- description += " requires audit_comment" if @options.key?(:comment_required)
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
@@ -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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Audited
2
- VERSION = "4.10.0"
4
+ VERSION = "5.0.0"
3
5
  end
@@ -1,9 +1,11 @@
1
- require 'rails/generators'
2
- require 'rails/generators/migration'
3
- require 'active_record'
4
- require 'rails/generators/active_record'
5
- require 'generators/audited/migration'
6
- require 'generators/audited/migration_helper'
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 'install.rb', 'db/migrate/install_audited.rb'
23
+ migration_template "install.rb", "db/migrate/install_audited.rb"
22
24
  end
23
25
  end
24
26
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Audited
2
4
  module Generators
3
5
  module Migration
@@ -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
- Rails::VERSION::MAJOR == 4 ? 'ActiveRecord::Migration' : "ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
7
+ "ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]"
6
8
  end
7
9
  end
8
10
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  add_column :audits, :association_id, :integer
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  add_column :audits, :comment, :string
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  add_column :audits, :remote_address, :string
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  add_column :audits, :request_uuid, :string
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  if index_exists?(:audits, [:auditable_type, :auditable_id], name: index_name)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  create_table :audits, :force => true do |t|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  if index_exists? :audits, [:association_id, :association_type], :name => 'association_index'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  rename_column :audits, :changes, :audited_changes
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  rename_column :audits, :auditable_parent_id, :association_id
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class <%= migration_class_name %> < <%= migration_parent %>
2
4
  def self.up
3
5
  fix_index_order_for [:associated_id, :associated_type], 'associated_index'
@@ -1,9 +1,11 @@
1
- require 'rails/generators'
2
- require 'rails/generators/migration'
3
- require 'active_record'
4
- require 'rails/generators/active_record'
5
- require 'generators/audited/migration'
6
- require 'generators/audited/migration_helper'
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?('comment')
32
+ yield :add_comment_to_audits unless columns.include?("comment")
31
33
 
32
- if columns.include?('changes')
34
+ if columns.include?("changes")
33
35
  yield :rename_changes_to_audited_changes
34
36
  end
35
37
 
36
- unless columns.include?('remote_address')
38
+ unless columns.include?("remote_address")
37
39
  yield :add_remote_address_to_audits
38
40
  end
39
41
 
40
- unless columns.include?('request_uuid')
42
+ unless columns.include?("request_uuid")
41
43
  yield :add_request_uuid_to_audits
42
44
  end
43
45
 
44
- unless columns.include?('association_id')
45
- if columns.include?('auditable_parent_id')
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?('associated_id')
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?('association_id')
56
+ if columns.include?("association_id")
55
57
  yield :rename_association_to_associated
56
58
  end
57
59
 
@@ -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
- TempModel.audited
41
+ TempModel1.audited
34
42
 
35
- record = TempModel.create
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
- TempModel.audited
53
+ TempModel2.audited
46
54
 
47
- record = TempModel.create
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, 'Joe')
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 = 'oops'
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 = 'Models::ActiveRecord::User'
109
- subject.username = 'joe'
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 = 'test'
121
- expect(subject.user).to eq('test')
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 = 'testing'
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 = 'test'
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('2018-01-01'))
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 a hash of the new values" do
240
- new_attributes = Audited::Audit.new(audited_changes: {a: [1, 2], b: [3, 4]}).new_attributes
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 a hash of the old values" do
247
- old_attributes = Audited::Audit.new(audited_changes: {a: [1, 2], b: [3, 4]}).old_attributes
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
- it "should be thread safe" do
297
- begin
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 if ActiveRecord::Base.connection.adapter_name != 'SQLite'
339
+ end
318
340
 
319
341
  it "should return the value from the yield block" do
320
- result = Audited::Audit.as_user('foo') do
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('foo') do
329
- raise StandardError.new('expected')
350
+ Audited::Audit.as_user("foo") do
351
+ raise StandardError.new("expected")
330
352
  end
331
- }.to raise_exception('expected')
353
+ }.to raise_exception("expected")
332
354
  expect(Audited.store[:audited_user]).to be_nil
333
355
  end
334
356
  end