audited 4.5.0 → 4.10.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 (40) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +0 -1
  3. data/.rubocop.yml +25 -0
  4. data/.travis.yml +37 -16
  5. data/Appraisals +33 -11
  6. data/CHANGELOG.md +151 -0
  7. data/README.md +125 -39
  8. data/gemfiles/rails42.gemfile +4 -1
  9. data/gemfiles/rails50.gemfile +4 -1
  10. data/gemfiles/rails51.gemfile +5 -2
  11. data/gemfiles/rails52.gemfile +10 -0
  12. data/gemfiles/rails60.gemfile +10 -0
  13. data/gemfiles/rails61.gemfile +10 -0
  14. data/lib/audited.rb +4 -2
  15. data/lib/audited/audit.rb +39 -14
  16. data/lib/audited/auditor.rb +223 -72
  17. data/lib/audited/rspec_matchers.rb +70 -21
  18. data/lib/audited/version.rb +1 -1
  19. data/lib/generators/audited/templates/add_version_to_auditable_index.rb +21 -0
  20. data/lib/generators/audited/templates/install.rb +2 -2
  21. data/lib/generators/audited/templates/revert_polymorphic_indexes_order.rb +20 -0
  22. data/lib/generators/audited/upgrade_generator.rb +9 -0
  23. data/spec/audited/audit_spec.rb +93 -4
  24. data/spec/audited/auditor_spec.rb +473 -57
  25. data/spec/audited/rspec_matchers_spec.rb +69 -0
  26. data/spec/audited/sweeper_spec.rb +15 -6
  27. data/spec/audited_spec_helpers.rb +16 -2
  28. data/spec/rails_app/app/assets/config/manifest.js +1 -0
  29. data/spec/rails_app/app/controllers/application_controller.rb +2 -0
  30. data/spec/rails_app/config/application.rb +5 -0
  31. data/spec/rails_app/config/database.yml +1 -0
  32. data/spec/spec_helper.rb +4 -1
  33. data/spec/support/active_record/models.rb +51 -4
  34. data/spec/support/active_record/schema.rb +4 -2
  35. data/test/db/version_6.rb +2 -0
  36. data/test/test_helper.rb +1 -2
  37. data/test/upgrade_generator_test.rb +10 -0
  38. metadata +62 -22
  39. data/gemfiles/rails40.gemfile +0 -9
  40. data/gemfiles/rails41.gemfile +0 -8
@@ -41,12 +41,12 @@ module Audited
41
41
  end
42
42
 
43
43
  def only(*fields)
44
- @options[:only] = fields.flatten
44
+ @options[:only] = fields.flatten.map(&:to_s)
45
45
  self
46
46
  end
47
47
 
48
48
  def except(*fields)
49
- @options[:except] = fields.flatten
49
+ @options[:except] = fields.flatten.map(&:to_s)
50
50
  self
51
51
  end
52
52
 
@@ -56,16 +56,13 @@ module Audited
56
56
  end
57
57
 
58
58
  def on(*actions)
59
- @options[:on] = actions.flatten
59
+ @options[:on] = actions.flatten.map(&:to_sym)
60
60
  self
61
61
  end
62
62
 
63
63
  def matches?(subject)
64
64
  @subject = subject
65
- auditing_enabled? &&
66
- associated_with_model? &&
67
- records_changes_to_specified_fields? &&
68
- comment_required_valid?
65
+ auditing_enabled? && required_checks_for_options_satisfied?
69
66
  end
70
67
 
71
68
  def failure_message
@@ -109,31 +106,83 @@ module Audited
109
106
  end
110
107
 
111
108
  def records_changes_to_specified_fields?
112
- if @options[:only] || @options[:except]
113
- if @options[:only]
114
- except = model_class.column_names - @options[:only].map(&:to_s)
115
- else
116
- except = model_class.default_ignored_attributes + Audited.ignored_attributes
117
- except |= @options[:except].collect(&:to_s) if @options[:except]
118
- end
109
+ ignored_fields = build_ignored_fields_from_options
110
+
111
+ expects "non audited columns (#{model_class.non_audited_columns.inspect}) to match (#{ignored_fields})"
112
+ model_class.non_audited_columns.to_set == ignored_fields.to_set
113
+ end
114
+
115
+ def comment_required_valid?
116
+ expects "to require audit_comment before #{model_class.audited_options[:on]} when comment required"
117
+ validate_callbacks_include_presence_of_comment? && destroy_callbacks_include_comment_required?
118
+ end
119
119
 
120
- expects "non audited columns (#{model_class.non_audited_columns.inspect}) to match (#{expect})"
121
- model_class.non_audited_columns =~ except
120
+ def only_audit_on_designated_callbacks?
121
+ {
122
+ create: [:after, :audit_create],
123
+ update: [:before, :audit_update],
124
+ destroy: [:before, :audit_destroy]
125
+ }.map do |(action, kind_callback)|
126
+ kind, callback = kind_callback
127
+ callbacks_for(action, kind: kind).include?(callback) if @options[:on].include?(action)
128
+ end.compact.all?
129
+ end
130
+
131
+ def validate_callbacks_include_presence_of_comment?
132
+ if @options[:comment_required] && audited_on_create_or_update?
133
+ callbacks_for(:validate).include?(:presence_of_audit_comment)
122
134
  else
123
135
  true
124
136
  end
125
137
  end
126
138
 
127
- def comment_required_valid?
128
- if @options[:comment_required]
129
- @subject.audit_comment = nil
139
+ def audited_on_create_or_update?
140
+ model_class.audited_options[:on].include?(:create) || model_class.audited_options[:on].include?(:update)
141
+ end
130
142
 
131
- expects "to be invalid when audit_comment is not specified"
132
- @subject.valid? == false && @subject.errors.key?(:audit_comment)
143
+ def destroy_callbacks_include_comment_required?
144
+ if @options[:comment_required] && model_class.audited_options[:on].include?(:destroy)
145
+ callbacks_for(:destroy).include?(:require_comment)
133
146
  else
134
147
  true
135
148
  end
136
149
  end
150
+
151
+ def requires_comment_before_callbacks?
152
+ [:create, :update, :destroy].map do |action|
153
+ if @options[:comment_required] && model_class.audited_options[:on].include?(action)
154
+ callbacks_for(action).include?(:require_comment)
155
+ end
156
+ end.compact.all?
157
+ end
158
+
159
+ def callbacks_for(action, kind: :before)
160
+ model_class.send("_#{action}_callbacks").select { |cb| cb.kind == kind }.map(&:filter)
161
+ end
162
+
163
+ def build_ignored_fields_from_options
164
+ default_ignored_attributes = model_class.default_ignored_attributes
165
+
166
+ if @options[:only].present?
167
+ (default_ignored_attributes | model_class.column_names) - @options[:only]
168
+ elsif @options[:except].present?
169
+ default_ignored_attributes | @options[:except]
170
+ else
171
+ default_ignored_attributes
172
+ end
173
+ end
174
+
175
+ def required_checks_for_options_satisfied?
176
+ {
177
+ only: :records_changes_to_specified_fields?,
178
+ except: :records_changes_to_specified_fields?,
179
+ comment_required: :comment_required_valid?,
180
+ associated_with: :associated_with_model?,
181
+ on: :only_audit_on_designated_callbacks?
182
+ }.map do |(option, check)|
183
+ send(check) if @options[option].present?
184
+ end.compact.all?
185
+ end
137
186
  end
138
187
 
139
188
  class AssociatedAuditMatcher # :nodoc:
@@ -1,3 +1,3 @@
1
1
  module Audited
2
- VERSION = "4.5.0"
2
+ VERSION = "4.10.0"
3
3
  end
@@ -0,0 +1,21 @@
1
+ class <%= migration_class_name %> < <%= migration_parent %>
2
+ def self.up
3
+ if index_exists?(:audits, [:auditable_type, :auditable_id], name: index_name)
4
+ remove_index :audits, name: index_name
5
+ add_index :audits, [:auditable_type, :auditable_id, :version], name: index_name
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ if index_exists?(:audits, [:auditable_type, :auditable_id, :version], name: index_name)
11
+ remove_index :audits, name: index_name
12
+ add_index :audits, [:auditable_type, :auditable_id], name: index_name
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def index_name
19
+ 'auditable_index'
20
+ end
21
+ end
@@ -17,8 +17,8 @@ class <%= migration_class_name %> < <%= migration_parent %>
17
17
  t.column :created_at, :datetime
18
18
  end
19
19
 
20
- add_index :audits, [:auditable_id, :auditable_type], :name => 'auditable_index'
21
- add_index :audits, [:associated_id, :associated_type], :name => 'associated_index'
20
+ add_index :audits, [:auditable_type, :auditable_id, :version], :name => 'auditable_index'
21
+ add_index :audits, [:associated_type, :associated_id], :name => 'associated_index'
22
22
  add_index :audits, [:user_id, :user_type], :name => 'user_index'
23
23
  add_index :audits, :request_uuid
24
24
  add_index :audits, :created_at
@@ -0,0 +1,20 @@
1
+ class <%= migration_class_name %> < <%= migration_parent %>
2
+ def self.up
3
+ fix_index_order_for [:associated_id, :associated_type], 'associated_index'
4
+ fix_index_order_for [:auditable_id, :auditable_type], 'auditable_index'
5
+ end
6
+
7
+ def self.down
8
+ fix_index_order_for [:associated_type, :associated_id], 'associated_index'
9
+ fix_index_order_for [:auditable_type, :auditable_id], 'auditable_index'
10
+ end
11
+
12
+ private
13
+
14
+ def fix_index_order_for(columns, index_name)
15
+ if index_exists? :audits, columns, name: index_name
16
+ remove_index :audits, name: index_name
17
+ add_index :audits, columns.reverse, name: index_name
18
+ end
19
+ end
20
+ end
@@ -25,6 +25,7 @@ module Audited
25
25
  def migrations_to_be_applied
26
26
  Audited::Audit.reset_column_information
27
27
  columns = Audited::Audit.columns.map(&:name)
28
+ indexes = Audited::Audit.connection.indexes(Audited::Audit.table_name)
28
29
 
29
30
  yield :add_comment_to_audits unless columns.include?('comment')
30
31
 
@@ -53,6 +54,14 @@ module Audited
53
54
  if columns.include?('association_id')
54
55
  yield :rename_association_to_associated
55
56
  end
57
+
58
+ if indexes.any? { |i| i.columns == %w[associated_id associated_type] }
59
+ yield :revert_polymorphic_indexes_order
60
+ end
61
+
62
+ if indexes.any? { |i| i.columns == %w[auditable_type auditable_id] }
63
+ yield :add_version_to_auditable_index
64
+ end
56
65
  end
57
66
  end
58
67
  end
@@ -1,5 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
+ SingleCov.covered! uncovered: 1 # Rails version check
4
+
3
5
  describe Audited::Audit do
4
6
  let(:user) { Models::ActiveRecord::User.new name: "Testing" }
5
7
 
@@ -51,8 +53,51 @@ describe Audited::Audit do
51
53
  end
52
54
  end
53
55
 
54
- describe "user=" do
56
+ describe "#audited_changes" do
57
+ let(:audit) { Audited.audit_class.new }
58
+
59
+ it "can unserialize yaml from text columns" do
60
+ audit.audited_changes = {foo: "bar"}
61
+ expect(audit.audited_changes).to eq foo: "bar"
62
+ end
55
63
 
64
+ it "does not unserialize from binary columns" do
65
+ allow(Audited::YAMLIfTextColumnType).to receive(:text_column?).and_return(false)
66
+ audit.audited_changes = {foo: "bar"}
67
+ expect(audit.audited_changes).to eq "{:foo=>\"bar\"}"
68
+ end
69
+ end
70
+
71
+ describe "#undo" do
72
+ let(:user) { Models::ActiveRecord::User.create(name: "John") }
73
+
74
+ it "undos changes" do
75
+ user.update_attribute(:name, 'Joe')
76
+ user.audits.last.undo
77
+ user.reload
78
+ expect(user.name).to eq("John")
79
+ end
80
+
81
+ it "undos destroy" do
82
+ user.destroy
83
+ user.audits.last.undo
84
+ user = Models::ActiveRecord::User.find_by(name: "John")
85
+ expect(user.name).to eq("John")
86
+ end
87
+
88
+ it "undos creation" do
89
+ user # trigger create
90
+ expect {user.audits.last.undo}.to change(Models::ActiveRecord::User, :count).by(-1)
91
+ end
92
+
93
+ it "fails when trying to undo unknown" do
94
+ audit = user.audits.last
95
+ audit.action = 'oops'
96
+ expect { audit.undo }.to raise_error("invalid action given oops")
97
+ end
98
+ end
99
+
100
+ describe "user=" do
56
101
  it "should be able to set the user to a model object" do
57
102
  subject.user = user
58
103
  expect(subject.user).to eq(user)
@@ -88,11 +133,9 @@ describe Audited::Audit do
88
133
  subject.user = user
89
134
  expect(subject.username).to be_nil
90
135
  end
91
-
92
136
  end
93
137
 
94
138
  describe "revision" do
95
-
96
139
  it "should recreate attributes" do
97
140
  user = Models::ActiveRecord::User.create name: "1"
98
141
  5.times {|i| user.update_attribute :name, (i + 2).to_s }
@@ -126,6 +169,34 @@ describe Audited::Audit do
126
169
  end
127
170
  end
128
171
 
172
+ describe ".collection_cache_key" do
173
+ if ActiveRecord::VERSION::MAJOR >= 5
174
+ it "uses created at" do
175
+ Audited::Audit.delete_all
176
+ audit = Models::ActiveRecord::User.create(name: "John").audits.last
177
+ audit.update_columns(created_at: Time.zone.parse('2018-01-01'))
178
+ expect(Audited::Audit.collection_cache_key).to match(/-20180101\d+$/)
179
+ end
180
+ else
181
+ it "is not defined" do
182
+ expect { Audited::Audit.collection_cache_key }.to raise_error(NoMethodError)
183
+ end
184
+ end
185
+ end
186
+
187
+ describe ".assign_revision_attributes" do
188
+ it "dups when frozen" do
189
+ user.freeze
190
+ assigned = Audited::Audit.assign_revision_attributes(user, name: "Bar")
191
+ expect(assigned.name).to eq "Bar"
192
+ end
193
+
194
+ it "ignores unassignable attributes" do
195
+ assigned = Audited::Audit.assign_revision_attributes(user, oops: "Bar")
196
+ expect(assigned.name).to eq "Testing"
197
+ end
198
+ end
199
+
129
200
  it "should set the version number on create" do
130
201
  user = Models::ActiveRecord::User.create! name: "Set Version Number"
131
202
  expect(user.audits.first.version).to eq(1)
@@ -191,6 +262,25 @@ describe Audited::Audit do
191
262
  end
192
263
  end
193
264
 
265
+ it "should support nested as_user" do
266
+ Audited::Audit.as_user("sidekiq") do
267
+ company = Models::ActiveRecord::Company.create name: "The auditors"
268
+ company.name = "The Auditors, Inc"
269
+ company.save
270
+ expect(company.audits[-1].user).to eq("sidekiq")
271
+
272
+ Audited::Audit.as_user(user) do
273
+ company.name = "NEW Auditors, Inc"
274
+ company.save
275
+ expect(company.audits[-1].user).to eq(user)
276
+ end
277
+
278
+ company.name = "LAST Auditors, Inc"
279
+ company.save
280
+ expect(company.audits[-1].user).to eq("sidekiq")
281
+ end
282
+ end
283
+
194
284
  it "should record usernames" do
195
285
  Audited::Audit.as_user(user.name) do
196
286
  company = Models::ActiveRecord::Company.create name: "The auditors"
@@ -241,6 +331,5 @@ describe Audited::Audit do
241
331
  }.to raise_exception('expected')
242
332
  expect(Audited.store[:audited_user]).to be_nil
243
333
  end
244
-
245
334
  end
246
335
  end
@@ -1,5 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
+ SingleCov.covered! uncovered: 13 # not testing proxy_respond_to? hack / 2 methods / deprecation of `version`
4
+
3
5
  describe Audited::Auditor do
4
6
 
5
7
  describe "configuration" do
@@ -17,6 +19,132 @@ describe Audited::Auditor do
17
19
  end
18
20
  end
19
21
 
22
+ context "should be configurable which conditions are audited" do
23
+ subject { ConditionalCompany.new.send(:auditing_enabled) }
24
+
25
+ context "when condition method is private" do
26
+ subject { ConditionalPrivateCompany.new.send(:auditing_enabled) }
27
+
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
+ it { is_expected.to be_truthy }
41
+ end
42
+
43
+ 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
+ context "when conditions are true" do
55
+ before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(true) }
56
+ it { is_expected.to be_truthy }
57
+ end
58
+
59
+ context "when conditions are false" do
60
+ before { allow_any_instance_of(ConditionalCompany).to receive(:public?).and_return(false) }
61
+ it { is_expected.to be_falsey }
62
+ end
63
+ end
64
+
65
+ context "when passing a Proc" do
66
+ 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
+ subject { InclusiveCompany.new.send(:auditing_enabled) }
75
+
76
+ it { is_expected.to be_truthy }
77
+ end
78
+
79
+ 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
+ subject { ExclusiveCompany.new.send(:auditing_enabled) }
87
+ it { is_expected.to be_falsey }
88
+ end
89
+ end
90
+ end
91
+
92
+ context "should be configurable which conditions aren't audited" do
93
+ 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
+ subject { ExclusionaryCompany.new.send(:auditing_enabled) }
105
+
106
+ context "when conditions are true" do
107
+ before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(true) }
108
+ it { is_expected.to be_falsey }
109
+ end
110
+
111
+ context "when conditions are false" do
112
+ before { allow_any_instance_of(ExclusionaryCompany).to receive(:non_profit?).and_return(false) }
113
+ it { is_expected.to be_truthy }
114
+ end
115
+ end
116
+
117
+ context "when using a proc" do
118
+ context "when conditions are true" do
119
+ before do
120
+ class ExclusionaryCompany < ::ActiveRecord::Base
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 }
132
+ end
133
+
134
+ context "when conditions are false" do
135
+ before do
136
+ class InclusiveCompany < ::ActiveRecord::Base
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 }
144
+ end
145
+ end
146
+ end
147
+
20
148
  it "should be configurable which attributes are not audited via ignored_attributes" do
21
149
  Audited.ignored_attributes = ['delta', 'top_secret', 'created_at']
22
150
  class Secret < ::ActiveRecord::Base
@@ -36,9 +164,14 @@ describe Audited::Auditor do
36
164
  end
37
165
 
38
166
  it "should not save non-audited columns" do
39
- Models::ActiveRecord::User.non_audited_columns = (Models::ActiveRecord::User.non_audited_columns << :favourite_device)
167
+ previous = Models::ActiveRecord::User.non_audited_columns
168
+ begin
169
+ Models::ActiveRecord::User.non_audited_columns += [:favourite_device]
40
170
 
41
- expect(create_user.audits.first.audited_changes.keys.any? { |col| ['favourite_device', 'created_at', 'updated_at', 'password'].include?( col ) }).to eq(false)
171
+ expect(create_user.audits.first.audited_changes.keys.any? { |col| ['favourite_device', 'created_at', 'updated_at', 'password'].include?( col ) }).to eq(false)
172
+ ensure
173
+ Models::ActiveRecord::User.non_audited_columns = previous
174
+ end
42
175
  end
43
176
 
44
177
  it "should not save other columns than specified in 'only' option" do
@@ -60,16 +193,68 @@ describe Audited::Auditor do
60
193
  expect(user.audits.last.audited_changes.keys).to eq(%w{password})
61
194
  end
62
195
 
63
- if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL' && Rails.version >= "4.2.0.0" # Postgres json and jsonb support was added in Rails 4.2
196
+ it "should save attributes not specified in 'except' option" do
197
+ user = Models::ActiveRecord::User.create
198
+ user.instance_eval do
199
+ def non_column_attr
200
+ @non_column_attr
201
+ end
202
+
203
+ def non_column_attr=(val)
204
+ attribute_will_change!("non_column_attr")
205
+ @non_column_attr = val
206
+ end
207
+ end
208
+
209
+ user.password = "password"
210
+ user.non_column_attr = "some value"
211
+ user.save!
212
+ expect(user.audits.last.audited_changes.keys).to eq(%w{non_column_attr})
213
+ end
214
+
215
+ it "should redact columns specified in 'redacted' option" do
216
+ redacted = Audited::Auditor::AuditedInstanceMethods::REDACTED
217
+ user = Models::ActiveRecord::UserRedactedPassword.create(password: "password")
218
+ user.save!
219
+ expect(user.audits.last.audited_changes['password']).to eq(redacted)
220
+ user.password = "new_password"
221
+ user.save!
222
+ expect(user.audits.last.audited_changes['password']).to eq([redacted, redacted])
223
+ end
224
+
225
+ it "should redact columns specified in 'redacted' option when there are multiple specified" do
226
+ redacted = Audited::Auditor::AuditedInstanceMethods::REDACTED
227
+ user =
228
+ Models::ActiveRecord::UserMultipleRedactedAttributes.create(
229
+ password: "password",
230
+ ssn: 123456789
231
+ )
232
+ user.save!
233
+ expect(user.audits.last.audited_changes['password']).to eq(redacted)
234
+ expect(user.audits.last.audited_changes['ssn']).to eq(redacted)
235
+ user.password = "new_password"
236
+ user.ssn = 987654321
237
+ user.save!
238
+ expect(user.audits.last.audited_changes['password']).to eq([redacted, redacted])
239
+ expect(user.audits.last.audited_changes['ssn']).to eq([redacted, redacted])
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
+ if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
64
249
  describe "'json' and 'jsonb' audited_changes column type" do
65
250
  let(:migrations_path) { SPEC_ROOT.join("support/active_record/postgres") }
66
251
 
67
252
  after do
68
- ActiveRecord::Migrator.rollback([migrations_path])
253
+ run_migrations(:down, migrations_path)
69
254
  end
70
255
 
71
256
  it "should work if column type is 'json'" do
72
- ActiveRecord::Migrator.up([migrations_path], 1)
257
+ run_migrations(:up, migrations_path, 1)
73
258
  Audited::Audit.reset_column_information
74
259
  expect(Audited::Audit.columns_hash["audited_changes"].sql_type).to eq("json")
75
260
 
@@ -80,7 +265,7 @@ describe Audited::Auditor do
80
265
  end
81
266
 
82
267
  it "should work if column type is 'jsonb'" do
83
- ActiveRecord::Migrator.up([migrations_path], 2)
268
+ run_migrations(:up, migrations_path, 2)
84
269
  Audited::Audit.reset_column_information
85
270
  expect(Audited::Audit.columns_hash["audited_changes"].sql_type).to eq("jsonb")
86
271
 
@@ -114,7 +299,7 @@ describe Audited::Auditor do
114
299
  end
115
300
 
116
301
  describe "on create" do
117
- let( :user ) { create_user audit_comment: "Create" }
302
+ let( :user ) { create_user status: :reliable, audit_comment: "Create" }
118
303
 
119
304
  it "should change the audit count" do
120
305
  expect {
@@ -138,6 +323,10 @@ describe Audited::Auditor do
138
323
  expect(user.audits.first.audited_changes).to eq(user.audited_attributes)
139
324
  end
140
325
 
326
+ it "should store enum value" do
327
+ expect(user.audits.first.audited_changes["status"]).to eq(1)
328
+ end
329
+
141
330
  it "should store comment" do
142
331
  expect(user.audits.first.comment).to eq('Create')
143
332
  end
@@ -156,7 +345,7 @@ describe Audited::Auditor do
156
345
 
157
346
  describe "on update" do
158
347
  before do
159
- @user = create_user( name: 'Brandon', audit_comment: 'Update' )
348
+ @user = create_user( name: 'Brandon', status: :active, audit_comment: 'Update' )
160
349
  end
161
350
 
162
351
  it "should save an audit" do
@@ -169,17 +358,22 @@ describe Audited::Auditor do
169
358
  end
170
359
 
171
360
  it "should set the action to 'update'" do
172
- @user.update_attributes name: 'Changed'
361
+ @user.update! name: 'Changed'
173
362
  expect(@user.audits.last.action).to eq('update')
174
363
  expect(Audited::Audit.updates.order(:id).last).to eq(@user.audits.last)
175
364
  expect(@user.audits.updates.last).to eq(@user.audits.last)
176
365
  end
177
366
 
178
367
  it "should store the changed attributes" do
179
- @user.update_attributes name: 'Changed'
368
+ @user.update! name: 'Changed'
180
369
  expect(@user.audits.last.audited_changes).to eq({ 'name' => ['Brandon', 'Changed'] })
181
370
  end
182
371
 
372
+ it "should store changed enum values" do
373
+ @user.update! status: 1
374
+ expect(@user.audits.last.audited_changes["status"]).to eq([0, 1])
375
+ end
376
+
183
377
  it "should store audit comment" do
184
378
  expect(@user.audits.last.comment).to eq('Update')
185
379
  end
@@ -187,12 +381,12 @@ describe Audited::Auditor do
187
381
  it "should not save an audit if only specified on create/destroy" do
188
382
  on_create_destroy = Models::ActiveRecord::OnCreateDestroy.create( name: 'Bart' )
189
383
  expect {
190
- on_create_destroy.update_attributes name: 'Changed'
384
+ on_create_destroy.update! name: 'Changed'
191
385
  }.to_not change( Audited::Audit, :count )
192
386
  end
193
387
 
194
388
  it "should not save an audit if the value doesn't change after type casting" do
195
- @user.update_attributes! logins: 0, activated: true
389
+ @user.update! logins: 0, activated: true
196
390
  expect { @user.update_attribute :logins, '0' }.to_not change( Audited::Audit, :count )
197
391
  expect { @user.update_attribute :activated, 1 }.to_not change( Audited::Audit, :count )
198
392
  expect { @user.update_attribute :activated, '1' }.to_not change( Audited::Audit, :count )
@@ -216,7 +410,7 @@ describe Audited::Auditor do
216
410
 
217
411
  describe "on destroy" do
218
412
  before do
219
- @user = create_user
413
+ @user = create_user(status: :active)
220
414
  end
221
415
 
222
416
  it "should save an audit" do
@@ -241,6 +435,11 @@ describe Audited::Auditor do
241
435
  expect(@user.audits.last.audited_changes).to eq(@user.audited_attributes)
242
436
  end
243
437
 
438
+ it "should store enum value" do
439
+ @user.destroy
440
+ expect(@user.audits.last.audited_changes["status"]).to eq(0)
441
+ end
442
+
244
443
  it "should be able to reconstruct a destroyed record without history" do
245
444
  @user.audits.delete_all
246
445
  @user.destroy
@@ -310,6 +509,77 @@ describe Audited::Auditor do
310
509
  end
311
510
  end
312
511
 
512
+ describe "max_audits" do
513
+ it "should respect global setting" do
514
+ stub_global_max_audits(10) do
515
+ expect(Models::ActiveRecord::User.audited_options[:max_audits]).to eq(10)
516
+ end
517
+ end
518
+
519
+ it "should respect per model setting" do
520
+ stub_global_max_audits(10) do
521
+ expect(Models::ActiveRecord::MaxAuditsUser.audited_options[:max_audits]).to eq(5)
522
+ end
523
+ end
524
+
525
+ it "should delete old audits when keeped amount exceeded" do
526
+ stub_global_max_audits(2) do
527
+ user = create_versions(2)
528
+ user.update(name: 'John')
529
+ expect(user.audits.pluck(:version)).to eq([2, 3])
530
+ end
531
+ end
532
+
533
+ it "should not delete old audits when keeped amount not exceeded" do
534
+ stub_global_max_audits(3) do
535
+ user = create_versions(2)
536
+ user.update(name: 'John')
537
+ expect(user.audits.pluck(:version)).to eq([1, 2, 3])
538
+ end
539
+ end
540
+
541
+ it "should delete old extra audits after introducing limit" do
542
+ stub_global_max_audits(nil) do
543
+ user = Models::ActiveRecord::User.create!(name: 'Brandon', username: 'brandon')
544
+ user.update!(name: 'Foobar')
545
+ user.update!(name: 'Awesome', username: 'keepers')
546
+ user.update!(activated: true)
547
+
548
+ Audited.max_audits = 3
549
+ Models::ActiveRecord::User.send(:normalize_audited_options)
550
+ user.update!(favourite_device: 'Android Phone')
551
+ audits = user.audits
552
+
553
+ expect(audits.count).to eq(3)
554
+ expect(audits[0].audited_changes).to include({'name' => ['Foobar', 'Awesome'], 'username' => ['brandon', 'keepers']})
555
+ expect(audits[1].audited_changes).to eq({'activated' => [nil, true]})
556
+ expect(audits[2].audited_changes).to eq({'favourite_device' => [nil, 'Android Phone']})
557
+ end
558
+ end
559
+
560
+ it "should add comment line for combined audit" do
561
+ stub_global_max_audits(2) do
562
+ user = Models::ActiveRecord::User.create!(name: 'Foobar 1')
563
+ user.update(name: 'Foobar 2', audit_comment: 'First audit comment')
564
+ user.update(name: 'Foobar 3', audit_comment: 'Second audit comment')
565
+ expect(user.audits.first.comment).to match(/First audit comment.+is the result of multiple/m)
566
+ end
567
+ end
568
+
569
+ def stub_global_max_audits(max_audits)
570
+ previous_max_audits = Audited.max_audits
571
+ previous_user_audited_options = Models::ActiveRecord::User.audited_options.dup
572
+ begin
573
+ Audited.max_audits = max_audits
574
+ Models::ActiveRecord::User.send(:normalize_audited_options) # reloads audited_options
575
+ yield
576
+ ensure
577
+ Audited.max_audits = previous_max_audits
578
+ Models::ActiveRecord::User.audited_options = previous_user_audited_options
579
+ end
580
+ end
581
+ end
582
+
313
583
  describe "revisions" do
314
584
  let( :user ) { create_versions }
315
585
 
@@ -328,8 +598,8 @@ describe Audited::Auditor do
328
598
 
329
599
  it "should set the attributes for each revision" do
330
600
  u = Models::ActiveRecord::User.create(name: 'Brandon', username: 'brandon')
331
- u.update_attributes name: 'Foobar'
332
- u.update_attributes name: 'Awesome', username: 'keepers'
601
+ u.update! name: 'Foobar'
602
+ u.update! name: 'Awesome', username: 'keepers'
333
603
 
334
604
  expect(u.revisions.size).to eql(3)
335
605
 
@@ -345,8 +615,8 @@ describe Audited::Auditor do
345
615
 
346
616
  it "access to only recent revisions" do
347
617
  u = Models::ActiveRecord::User.create(name: 'Brandon', username: 'brandon')
348
- u.update_attributes name: 'Foobar'
349
- u.update_attributes name: 'Awesome', username: 'keepers'
618
+ u.update! name: 'Foobar'
619
+ u.update! name: 'Awesome', username: 'keepers'
350
620
 
351
621
  expect(u.revisions(2).size).to eq(2)
352
622
 
@@ -363,7 +633,7 @@ describe Audited::Auditor do
363
633
  end
364
634
 
365
635
  it "should ignore attributes that have been deleted" do
366
- user.audits.last.update_attributes audited_changes: {old_attribute: 'old value'}
636
+ user.audits.last.update! audited_changes: {old_attribute: 'old value'}
367
637
  expect { user.revisions }.to_not raise_error
368
638
  end
369
639
  end
@@ -378,21 +648,21 @@ describe Audited::Auditor do
378
648
  it "should find the given revision" do
379
649
  revision = user.revision(3)
380
650
  expect(revision).to be_a_kind_of( Models::ActiveRecord::User )
381
- expect(revision.version).to eq(3)
651
+ expect(revision.audit_version).to eq(3)
382
652
  expect(revision.name).to eq('Foobar 3')
383
653
  end
384
654
 
385
655
  it "should find the previous revision with :previous" do
386
656
  revision = user.revision(:previous)
387
- expect(revision.version).to eq(4)
657
+ expect(revision.audit_version).to eq(4)
388
658
  #expect(revision).to eq(user.revision(4))
389
659
  expect(revision.attributes).to eq(user.revision(4).attributes)
390
660
  end
391
661
 
392
662
  it "should be able to get the previous revision repeatedly" do
393
663
  previous = user.revision(:previous)
394
- expect(previous.version).to eq(4)
395
- expect(previous.revision(:previous).version).to eq(3)
664
+ expect(previous.audit_version).to eq(4)
665
+ expect(previous.revision(:previous).audit_version).to eq(3)
396
666
  end
397
667
 
398
668
  it "should be able to set protected attributes" do
@@ -412,8 +682,8 @@ describe Audited::Auditor do
412
682
 
413
683
  it "should set the attributes for each revision" do
414
684
  u = Models::ActiveRecord::User.create(name: 'Brandon', username: 'brandon')
415
- u.update_attributes name: 'Foobar'
416
- u.update_attributes name: 'Awesome', username: 'keepers'
685
+ u.update! name: 'Foobar'
686
+ u.update! name: 'Awesome', username: 'keepers'
417
687
 
418
688
  expect(u.revision(3).name).to eq('Awesome')
419
689
  expect(u.revision(3).username).to eq('keepers')
@@ -425,6 +695,16 @@ describe Audited::Auditor do
425
695
  expect(u.revision(1).username).to eq('brandon')
426
696
  end
427
697
 
698
+ it "should correctly restore revision with enum" do
699
+ u = Models::ActiveRecord::User.create(status: :active)
700
+ u.update_attribute(:status, :reliable)
701
+ u.update_attribute(:status, :banned)
702
+
703
+ expect(u.revision(3)).to be_banned
704
+ expect(u.revision(2)).to be_reliable
705
+ expect(u.revision(1)).to be_active
706
+ end
707
+
428
708
  it "should be able to get time for first revision" do
429
709
  suspended_at = Time.zone.now
430
710
  u = Models::ActiveRecord::User.create(suspended_at: suspended_at)
@@ -452,6 +732,10 @@ describe Audited::Auditor do
452
732
  user.revision(1).save!
453
733
  }.to change( Models::ActiveRecord::User, :count ).by(1)
454
734
  end
735
+
736
+ it "should return nil for values greater than the number of revisions" do
737
+ expect(user.revision(user.revisions.count + 1)).to be_nil
738
+ end
455
739
  end
456
740
 
457
741
  describe "revision_at" do
@@ -461,8 +745,8 @@ describe Audited::Auditor do
461
745
  audit = user.audits.first
462
746
  audit.created_at = 1.hour.ago
463
747
  audit.save!
464
- user.update_attributes name: 'updated'
465
- expect(user.revision_at( 2.minutes.ago ).version).to eq(1)
748
+ user.update! name: 'updated'
749
+ expect(user.revision_at( 2.minutes.ago ).audit_version).to eq(1)
466
750
  end
467
751
 
468
752
  it "should be nil if given a time before audits" do
@@ -470,6 +754,33 @@ describe Audited::Auditor do
470
754
  end
471
755
  end
472
756
 
757
+ describe "own_and_associated_audits" do
758
+ it "should return audits for self and associated audits" do
759
+ owner = Models::ActiveRecord::Owner.create!
760
+ company = owner.companies.create!
761
+ company.update!(name: "Collective Idea")
762
+
763
+ other_owner = Models::ActiveRecord::Owner.create!
764
+ other_owner.companies.create!
765
+
766
+ expect(owner.own_and_associated_audits).to match_array(owner.audits + company.audits)
767
+ end
768
+
769
+ it "should order audits by creation time" do
770
+ owner = Models::ActiveRecord::Owner.create!
771
+ first_audit = owner.audits.first
772
+ first_audit.update_column(:created_at, 1.year.ago)
773
+
774
+ company = owner.companies.create!
775
+ second_audit = company.audits.first
776
+ second_audit.update_column(:created_at, 1.month.ago)
777
+
778
+ company.update!(name: "Collective Idea")
779
+ third_audit = company.audits.last
780
+ expect(owner.own_and_associated_audits.to_a).to eq([third_audit, second_audit, first_audit])
781
+ end
782
+ end
783
+
473
784
  describe "without auditing" do
474
785
  it "should not save an audit when calling #save_without_auditing" do
475
786
  expect {
@@ -490,72 +801,162 @@ describe Audited::Auditor do
490
801
  end
491
802
 
492
803
  it "should be thread safe using a #without_auditing block" do
493
- begin
494
- t1 = Thread.new do
495
- expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
496
- Models::ActiveRecord::User.without_auditing do
497
- expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
498
- Models::ActiveRecord::User.create!( name: 'Bart' )
499
- sleep 1
500
- expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
501
- end
502
- expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
804
+ skip if Models::ActiveRecord::User.connection.class.name.include?("SQLite")
805
+
806
+ t1 = Thread.new do
807
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
808
+ Models::ActiveRecord::User.without_auditing do
809
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
810
+ Models::ActiveRecord::User.create!( name: 'Bart' )
811
+ sleep 1
812
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
503
813
  end
814
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
815
+ end
816
+
817
+ t2 = Thread.new do
818
+ sleep 0.5
819
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
820
+ Models::ActiveRecord::User.create!( name: 'Lisa' )
821
+ end
822
+ t1.join
823
+ t2.join
824
+
825
+ expect(Models::ActiveRecord::User.find_by_name('Bart').audits.count).to eq(0)
826
+ expect(Models::ActiveRecord::User.find_by_name('Lisa').audits.count).to eq(1)
827
+ end
828
+
829
+ it "should not save an audit when auditing is globally disabled" do
830
+ expect(Audited.auditing_enabled).to eq(true)
831
+ Audited.auditing_enabled = false
832
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
833
+
834
+ user = create_user
835
+ expect(user.audits.count).to eq(0)
836
+
837
+ Audited.auditing_enabled = true
838
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
839
+
840
+ user.update!(name: 'Test')
841
+ expect(user.audits.count).to eq(1)
842
+ Models::ActiveRecord::User.enable_auditing
843
+ end
844
+ end
845
+
846
+ describe "with auditing" do
847
+ it "should save an audit when calling #save_with_auditing" do
848
+ expect {
849
+ u = Models::ActiveRecord::User.new(name: 'Brandon')
850
+ Models::ActiveRecord::User.auditing_enabled = false
851
+ expect(u.save_with_auditing).to eq(true)
852
+ Models::ActiveRecord::User.auditing_enabled = true
853
+ }.to change( Audited::Audit, :count ).by(1)
854
+ end
855
+
856
+ it "should save an audit inside of the #with_auditing block" do
857
+ expect {
858
+ Models::ActiveRecord::User.auditing_enabled = false
859
+ Models::ActiveRecord::User.with_auditing { Models::ActiveRecord::User.create!( name: 'Brandon' ) }
860
+ Models::ActiveRecord::User.auditing_enabled = true
861
+ }.to change( Audited::Audit, :count ).by(1)
862
+ end
504
863
 
505
- t2 = Thread.new do
506
- sleep 0.5
864
+ it "should reset auditing status even it raises an exception" do
865
+ Models::ActiveRecord::User.disable_auditing
866
+ Models::ActiveRecord::User.with_auditing { raise } rescue nil
867
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
868
+ Models::ActiveRecord::User.enable_auditing
869
+ end
870
+
871
+ it "should be thread safe using a #with_auditing block" do
872
+ skip if Models::ActiveRecord::User.connection.class.name.include?("SQLite")
873
+
874
+ t1 = Thread.new do
875
+ Models::ActiveRecord::User.disable_auditing
876
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
877
+ Models::ActiveRecord::User.with_auditing do
878
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
879
+
880
+ Models::ActiveRecord::User.create!( name: 'Shaggy' )
881
+ sleep 1
507
882
  expect(Models::ActiveRecord::User.auditing_enabled).to eq(true)
508
- Models::ActiveRecord::User.create!( name: 'Lisa' )
509
883
  end
510
- t1.join
511
- t2.join
884
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
885
+ Models::ActiveRecord::User.enable_auditing
886
+ end
512
887
 
513
- expect(Models::ActiveRecord::User.find_by_name('Bart').audits.count).to eq(0)
514
- expect(Models::ActiveRecord::User.find_by_name('Lisa').audits.count).to eq(1)
515
- rescue ActiveRecord::StatementInvalid
516
- STDERR.puts "Thread safety tests cannot be run with SQLite"
888
+ t2 = Thread.new do
889
+ sleep 0.5
890
+ Models::ActiveRecord::User.disable_auditing
891
+ expect(Models::ActiveRecord::User.auditing_enabled).to eq(false)
892
+ Models::ActiveRecord::User.create!( name: 'Scooby' )
893
+ Models::ActiveRecord::User.enable_auditing
517
894
  end
895
+ t1.join
896
+ t2.join
897
+
898
+ Models::ActiveRecord::User.enable_auditing
899
+ expect(Models::ActiveRecord::User.find_by_name('Shaggy').audits.count).to eq(1)
900
+ expect(Models::ActiveRecord::User.find_by_name('Scooby').audits.count).to eq(0)
518
901
  end
519
902
  end
520
903
 
521
904
  describe "comment required" do
522
905
 
523
906
  describe "on create" do
524
- it "should not validate when audit_comment is not supplied" do
525
- expect(Models::ActiveRecord::CommentRequiredUser.new).not_to be_valid
907
+ it "should not validate when audit_comment is not supplied when initialized" do
908
+ expect(Models::ActiveRecord::CommentRequiredUser.new(name: 'Foo')).not_to be_valid
909
+ end
910
+
911
+ it "should not validate when audit_comment is not supplied trying to create" do
912
+ expect(Models::ActiveRecord::CommentRequiredUser.create(name: 'Foo')).not_to be_valid
526
913
  end
527
914
 
528
915
  it "should validate when audit_comment is supplied" do
529
- expect(Models::ActiveRecord::CommentRequiredUser.new( audit_comment: 'Create')).to be_valid
916
+ expect(Models::ActiveRecord::CommentRequiredUser.create(name: 'Foo', audit_comment: 'Create')).to be_valid
917
+ end
918
+
919
+ it "should validate when audit_comment is not supplied, and creating is not being audited" do
920
+ expect(Models::ActiveRecord::OnUpdateCommentRequiredUser.create(name: 'Foo')).to be_valid
921
+ expect(Models::ActiveRecord::OnDestroyCommentRequiredUser.create(name: 'Foo')).to be_valid
530
922
  end
531
923
 
532
924
  it "should validate when audit_comment is not supplied, and auditing is disabled" do
533
925
  Models::ActiveRecord::CommentRequiredUser.disable_auditing
534
- expect(Models::ActiveRecord::CommentRequiredUser.new).to be_valid
926
+ expect(Models::ActiveRecord::CommentRequiredUser.create(name: 'Foo')).to be_valid
535
927
  Models::ActiveRecord::CommentRequiredUser.enable_auditing
536
928
  end
537
929
  end
538
930
 
539
931
  describe "on update" do
540
932
  let( :user ) { Models::ActiveRecord::CommentRequiredUser.create!( audit_comment: 'Create' ) }
933
+ let( :on_create_user ) { Models::ActiveRecord::OnDestroyCommentRequiredUser.create }
934
+ let( :on_destroy_user ) { Models::ActiveRecord::OnDestroyCommentRequiredUser.create }
541
935
 
542
936
  it "should not validate when audit_comment is not supplied" do
543
- expect(user.update_attributes(name: 'Test')).to eq(false)
937
+ expect(user.update(name: 'Test')).to eq(false)
938
+ end
939
+
940
+ it "should validate when audit_comment is not supplied, and updating is not being audited" do
941
+ expect(on_create_user.update(name: 'Test')).to eq(true)
942
+ expect(on_destroy_user.update(name: 'Test')).to eq(true)
544
943
  end
545
944
 
546
945
  it "should validate when audit_comment is supplied" do
547
- expect(user.update_attributes(name: 'Test', audit_comment: 'Update')).to eq(true)
946
+ expect(user.update(name: 'Test', audit_comment: 'Update')).to eq(true)
548
947
  end
549
948
 
550
949
  it "should validate when audit_comment is not supplied, and auditing is disabled" do
551
950
  Models::ActiveRecord::CommentRequiredUser.disable_auditing
552
- expect(user.update_attributes(name: 'Test')).to eq(true)
951
+ expect(user.update(name: 'Test')).to eq(true)
553
952
  Models::ActiveRecord::CommentRequiredUser.enable_auditing
554
953
  end
555
954
  end
556
955
 
557
956
  describe "on destroy" do
558
957
  let( :user ) { Models::ActiveRecord::CommentRequiredUser.create!( audit_comment: 'Create' )}
958
+ let( :on_create_user ) { Models::ActiveRecord::OnCreateCommentRequiredUser.create!( audit_comment: 'Create' ) }
959
+ let( :on_update_user ) { Models::ActiveRecord::OnUpdateCommentRequiredUser.create }
559
960
 
560
961
  it "should not validate when audit_comment is not supplied" do
561
962
  expect(user.destroy).to eq(false)
@@ -566,6 +967,11 @@ describe Audited::Auditor do
566
967
  expect(user.destroy).to eq(user)
567
968
  end
568
969
 
970
+ it "should validate when audit_comment is not supplied, and destroying is not being audited" do
971
+ expect(on_create_user.destroy).to eq(on_create_user)
972
+ expect(on_update_user.destroy).to eq(on_update_user)
973
+ end
974
+
569
975
  it "should validate when audit_comment is not supplied, and auditing is disabled" do
570
976
  Models::ActiveRecord::CommentRequiredUser.disable_auditing
571
977
  expect(user.destroy).to eq(user)
@@ -575,6 +981,16 @@ describe Audited::Auditor do
575
981
 
576
982
  end
577
983
 
984
+ describe "no update with comment only" do
985
+ let( :user ) { Models::ActiveRecord::NoUpdateWithCommentOnlyUser.create }
986
+
987
+ it "does not create an audit when only an audit_comment is present" do
988
+ user.audit_comment = "Comment"
989
+ expect { user.save! }.to_not change( Audited::Audit, :count )
990
+ end
991
+
992
+ end
993
+
578
994
  describe "attr_protected and attr_accessible" do
579
995
 
580
996
  it "should not raise error when attr_accessible is set and protected is false" do
@@ -596,7 +1012,7 @@ describe Audited::Auditor do
596
1012
  it "should record user objects" do
597
1013
  Models::ActiveRecord::Company.audit_as( user ) do
598
1014
  company = Models::ActiveRecord::Company.create name: 'The auditors'
599
- company.update_attributes name: 'The Auditors'
1015
+ company.update! name: 'The Auditors'
600
1016
 
601
1017
  company.audits.each do |audit|
602
1018
  expect(audit.user).to eq(user)
@@ -607,7 +1023,7 @@ describe Audited::Auditor do
607
1023
  it "should record usernames" do
608
1024
  Models::ActiveRecord::Company.audit_as( user.name ) do
609
1025
  company = Models::ActiveRecord::Company.create name: 'The auditors'
610
- company.update_attributes name: 'The Auditors'
1026
+ company.update! name: 'The Auditors'
611
1027
 
612
1028
  company.audits.each do |audit|
613
1029
  expect(audit.user).to eq(user.name)
@@ -617,7 +1033,7 @@ describe Audited::Auditor do
617
1033
  end
618
1034
 
619
1035
  describe "after_audit" do
620
- let( :user ) { user = Models::ActiveRecord::UserWithAfterAudit.new }
1036
+ let( :user ) { Models::ActiveRecord::UserWithAfterAudit.new }
621
1037
 
622
1038
  it "should invoke after_audit callback on create" do
623
1039
  expect(user.bogus_attr).to be_nil
@@ -627,7 +1043,7 @@ describe Audited::Auditor do
627
1043
  end
628
1044
 
629
1045
  describe "around_audit" do
630
- let( :user ) { user = Models::ActiveRecord::UserWithAfterAudit.new }
1046
+ let( :user ) { Models::ActiveRecord::UserWithAfterAudit.new }
631
1047
 
632
1048
  it "should invoke around_audit callback on create" do
633
1049
  expect(user.around_attr).to be_nil
@@ -642,7 +1058,7 @@ describe Audited::Auditor do
642
1058
  expect(company.type).to eq("Models::ActiveRecord::Company::STICompany")
643
1059
  expect {
644
1060
  Models::ActiveRecord::Company.auditing_enabled = false
645
- company.update_attributes name: 'STI auditors'
1061
+ company.update! name: 'STI auditors'
646
1062
  Models::ActiveRecord::Company.auditing_enabled = true
647
1063
  }.to_not change( Audited::Audit, :count )
648
1064
  end