acts_as_audited_customized 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,37 @@
1
+ module CollectiveIdea #:nodoc:
2
+ module ActionController #:nodoc:
3
+ module Audited #:nodoc:
4
+ def audit(*models)
5
+ ActiveSupport::Deprecation.warn("#audit is deprecated. Declare #acts_as_audited in your models.", caller)
6
+
7
+ options = models.extract_options!
8
+
9
+ # Parse the options hash looking for classes
10
+ options.each_key do |key|
11
+ models << [key, options.delete(key)] if key.is_a?(Class)
12
+ end
13
+
14
+ models.each do |(model, model_options)|
15
+ model.send :acts_as_audited, model_options || {}
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ class AuditSweeper < ActionController::Caching::Sweeper #:nodoc:
23
+ def before_create(audit)
24
+ audit.send("#{CollectiveIdea::Acts::Audited.human_model}=", current_user) unless audit.send(CollectiveIdea::Acts::Audited.human_model)
25
+ end
26
+
27
+ def current_user
28
+ method = "current_#{CollectiveIdea::Acts::Audited.human_model}"
29
+ controller.send(method) if controller.respond_to?(method, true)
30
+ end
31
+ end
32
+
33
+ ActionController::Base.class_eval do
34
+ extend CollectiveIdea::ActionController::Audited
35
+ cache_sweeper :audit_sweeper
36
+ end
37
+ Audit.add_observer(AuditSweeper.instance)
data/rails/init.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'acts_as_audited'
2
+
3
+ ActiveRecord::Base.send :include, CollectiveIdea::Acts::Audited
4
+
5
+ if defined?(ActionController) and defined?(ActionController::Base)
6
+ require 'acts_as_audited/audit_sweeper'
7
+ end
@@ -0,0 +1,374 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ module CollectiveIdea
4
+ module Acts
5
+ class AuditedTest < Test::Unit::TestCase
6
+ should "include instance methods" do
7
+ User.new.should be_kind_of(CollectiveIdea::Acts::Audited::InstanceMethods)
8
+ end
9
+
10
+ should "extend singleton methods" do
11
+ User.should be_kind_of(CollectiveIdea::Acts::Audited::SingletonMethods)
12
+ end
13
+
14
+ ['created_at', 'updated_at', 'created_on', 'updated_on', 'lock_version', 'id', 'password'].each do |column|
15
+ should "not audit #{column}" do
16
+ User.non_audited_columns.should include(column)
17
+ end
18
+ end
19
+
20
+ should "not save non-audited columns" do
21
+ create_user.audits.first.changes.keys.any?{|col| ['created_at', 'updated_at', 'password'].include? col}.should be(false)
22
+ end
23
+
24
+ context "on create" do
25
+ setup { @user = create_user }
26
+
27
+ should_change 'Audit.count', :by => 1
28
+
29
+ should 'create associated audit' do
30
+ @user.audits.count.should == 1
31
+ end
32
+
33
+ should "set the action to 'create'" do
34
+ @user.audits.first.action.should == 'create'
35
+ end
36
+
37
+ should "store all the audited attributes" do
38
+ @user.audits.first.changes.should == @user.audited_attributes
39
+ end
40
+
41
+ should "not audit an attribute which is excepted if specified on create and on destroy" do
42
+ on_create_destroy_except_name = OnCreateDestroyExceptName.create(:name => 'Bart')
43
+ on_create_destroy_except_name.audits.first.changes.keys.any?{|col| ['name'].include? col}.should be(false)
44
+ end
45
+
46
+ should "not save an audit if only specified on update and on destroy" do
47
+ lambda { on_update_destroy = OnUpdateDestroy.create(:name => 'Bart') }.should_not change { Audit.count }
48
+ end
49
+ end
50
+
51
+ context "on update" do
52
+ setup do
53
+ @user = create_user(:name => 'Brandon')
54
+ end
55
+
56
+ should "save an audit" do
57
+ lambda { @user.update_attribute(:name, "Someone") }.should change { @user.audits.count }.by(1)
58
+ lambda { @user.update_attribute(:name, "Someone else") }.should change { @user.audits.count }.by(1)
59
+ end
60
+
61
+ should "not save an audit if the record is not changed" do
62
+ lambda { @user.save! }.should_not change { Audit.count }
63
+ end
64
+
65
+ should "set the action to 'update'" do
66
+ @user.update_attributes :name => 'Changed'
67
+ @user.audits.last.action.should == 'update'
68
+ end
69
+
70
+ should "store the changed attributes" do
71
+ @user.update_attributes :name => 'Changed'
72
+ @user.audits.last.changes.should == {'name' => ['Brandon', 'Changed']}
73
+ end
74
+
75
+ # Dirty tracking in Rails 2.0-2.2 had issues with type casting
76
+ if ActiveRecord::VERSION::STRING >= '2.3'
77
+ should "not save an audit if the value doesn't change after type casting" do
78
+ @user.update_attributes! :logins => 0, :activated => true
79
+ lambda { @user.update_attribute :logins, '0' }.should_not change { Audit.count }
80
+ lambda { @user.update_attribute :activated, 1 }.should_not change { Audit.count }
81
+ lambda { @user.update_attribute :activated, '1' }.should_not change { Audit.count }
82
+ end
83
+ end
84
+
85
+ should "not save an audit if only specified on create and on destroy" do
86
+ on_create_destroy = OnCreateDestroy.create(:name => 'Bart')
87
+ lambda { on_create_destroy.update_attributes :name => 'Changed' }.should_not change { Audit.count }
88
+ end
89
+ end
90
+
91
+ context "on destroy" do
92
+ setup do
93
+ @user = create_user
94
+ end
95
+
96
+ should "save an audit" do
97
+ lambda { @user.destroy }.should change { Audit.count }.by(1)
98
+ @user.audits.size.should == 2
99
+ end
100
+
101
+ should "set the action to 'destroy'" do
102
+ @user.destroy
103
+ @user.audits.last.action.should == 'destroy'
104
+ end
105
+
106
+ should "store all of the audited attributes" do
107
+ @user.destroy
108
+ @user.audits.last.changes.should == @user.audited_attributes
109
+ end
110
+
111
+ should "be able to reconstruct destroyed record without history" do
112
+ @user.audits.delete_all
113
+ @user.destroy
114
+ revision = @user.audits.first.revision
115
+ revision.name.should == @user.name
116
+ end
117
+
118
+ should "not save an audit if only specified on create and on update" do
119
+ on_create_update = OnCreateUpdate.create(:name => 'Bart')
120
+ lambda { on_create_update.destroy }.should_not change { Audit.count }
121
+ end
122
+ end
123
+
124
+ context "dirty tracking" do
125
+ setup do
126
+ @user = create_user
127
+ end
128
+
129
+ should "not be changed when the record is saved" do
130
+ u = User.new(:name => 'Brandon')
131
+ u.changed?.should be(true)
132
+ u.save
133
+ u.changed?.should be(false)
134
+ end
135
+
136
+ should "be changed when an attribute has been changed" do
137
+ @user.name = "Bobby"
138
+ @user.changed?.should be(true)
139
+ @user.name_changed?.should be(true)
140
+ @user.username_changed?.should be(false)
141
+ end
142
+
143
+ # Dirty tracking in Rails 2.0-2.2 had issues with type casting
144
+ if ActiveRecord::VERSION::STRING >= '2.3'
145
+ should "not be changed if the value doesn't change after type casting" do
146
+ @user.update_attributes! :logins => 0, :activated => true
147
+ @user.logins = '0'
148
+ @user.changed?.should be(false)
149
+ end
150
+ end
151
+
152
+ end
153
+
154
+ context "revisions" do
155
+ setup do
156
+ @user = create_versions
157
+ end
158
+
159
+ should "be an Array of Users" do
160
+ @user.revisions.should be_kind_of(Array)
161
+ @user.revisions.each {|version| version.should be_kind_of(User) }
162
+ end
163
+
164
+ should "have one revision for a new record" do
165
+ create_user.revisions.size.should == 1
166
+ end
167
+
168
+ should "have one revision for each audit" do
169
+ @user.revisions.size.should == @user.audits.size
170
+ end
171
+
172
+ should "set the attributes for each revision" do
173
+ u = User.create(:name => 'Brandon', :username => 'brandon')
174
+ u.update_attributes :name => 'Foobar'
175
+ u.update_attributes :name => 'Awesome', :username => 'keepers'
176
+
177
+ u.revisions.size.should == 3
178
+
179
+ u.revisions[0].name.should == 'Brandon'
180
+ u.revisions[0].username.should == 'brandon'
181
+
182
+ u.revisions[1].name.should == 'Foobar'
183
+ u.revisions[1].username.should == 'brandon'
184
+
185
+ u.revisions[2].name.should == 'Awesome'
186
+ u.revisions[2].username.should == 'keepers'
187
+ end
188
+
189
+ should "access to only recent revisions" do
190
+ u = User.create(:name => 'Brandon', :username => 'brandon')
191
+ u.update_attributes :name => 'Foobar'
192
+ u.update_attributes :name => 'Awesome', :username => 'keepers'
193
+
194
+ u.revisions(2).size.should == 2
195
+
196
+ u.revisions(2)[0].name.should == 'Foobar'
197
+ u.revisions(2)[0].username.should == 'brandon'
198
+
199
+ u.revisions(2)[1].name.should == 'Awesome'
200
+ u.revisions(2)[1].username.should == 'keepers'
201
+ end
202
+
203
+ should "be empty if no audits exist" do
204
+ @user.audits.delete_all
205
+ @user.revisions.empty?.should be(true)
206
+ end
207
+
208
+ should "ignore attributes that have been deleted" do
209
+ @user.audits.last.update_attributes :changes => {:old_attribute => 'old value'}
210
+ lambda { @user.revisions }.should_not raise_error
211
+ end
212
+
213
+ end
214
+
215
+ context "revision" do
216
+ setup do
217
+ @user = create_versions(5)
218
+ end
219
+
220
+ should "maintain identity" do
221
+ @user.revision(1).should == @user
222
+ end
223
+
224
+ should "find the given revision" do
225
+ revision = @user.revision(3)
226
+ revision.should be_kind_of(User)
227
+ revision.version.should == 3
228
+ revision.name.should == 'Foobar 3'
229
+ end
230
+
231
+ should "find the previous revision with :previous" do
232
+ revision = @user.revision(:previous)
233
+ revision.version.should == 4
234
+ revision.should == @user.revision(4)
235
+ end
236
+
237
+ should "be able to get the previous revision repeatedly" do
238
+ previous = @user.revision(:previous)
239
+ previous.version.should == 4
240
+ previous.revision(:previous).version.should == 3
241
+ end
242
+
243
+ should "be able to set protected attributes" do
244
+ u = User.create(:name => 'Brandon')
245
+ u.update_attribute :logins, 1
246
+ u.update_attribute :logins, 2
247
+
248
+ u.revision(3).logins.should == 2
249
+ u.revision(2).logins.should == 1
250
+ u.revision(1).logins.should == 0
251
+ end
252
+
253
+ should "set attributes directly" do
254
+ u = User.create(:name => '<Joe>')
255
+ u.revision(1).name.should == '&lt;Joe&gt;'
256
+ end
257
+
258
+ should "set the attributes for each revision" do
259
+ u = User.create(:name => 'Brandon', :username => 'brandon')
260
+ u.update_attributes :name => 'Foobar'
261
+ u.update_attributes :name => 'Awesome', :username => 'keepers'
262
+
263
+ u.revision(3).name.should == 'Awesome'
264
+ u.revision(3).username.should == 'keepers'
265
+
266
+ u.revision(2).name.should == 'Foobar'
267
+ u.revision(2).username.should == 'brandon'
268
+
269
+ u.revision(1).name.should == 'Brandon'
270
+ u.revision(1).username.should == 'brandon'
271
+ end
272
+
273
+ should "not raise an error when no previous audits exist" do
274
+ @user.audits.destroy_all
275
+ lambda{ @user.revision(:previous) }.should_not raise_error
276
+ end
277
+
278
+ should "mark revision's attributes as changed" do
279
+ @user.revision(1).name_changed?.should be(true)
280
+ end
281
+
282
+ should "record new audit when saving revision" do
283
+ lambda { @user.revision(1).save! }.should change { @user.audits.count }.by(1)
284
+ end
285
+
286
+ end
287
+
288
+ context "revision_at" do
289
+ should "find the latest revision before the given time" do
290
+ u = create_user
291
+ Audit.update(u.audits.first.id, :created_at => 1.hour.ago)
292
+ u.update_attributes :name => 'updated'
293
+ u.revision_at(2.minutes.ago).version.should == 1
294
+ end
295
+
296
+ should "be nil if given a time before audits" do
297
+ create_user.revision_at(1.week.ago).should be(nil)
298
+ end
299
+
300
+ end
301
+
302
+ context "without auditing" do
303
+
304
+ should "not save an audit when calling #save_without_auditing" do
305
+ lambda {
306
+ u = User.new(:name => 'Brandon')
307
+ u.save_without_auditing.should be(true)
308
+ }.should_not change { Audit.count }
309
+ end
310
+
311
+ should "not save an audit inside of the #without_auditing block" do
312
+ lambda do
313
+ User.without_auditing { User.create(:name => 'Brandon') }
314
+ end.should_not change { Audit.count }
315
+ end
316
+ end
317
+
318
+ context "attr_protected and attr_accessible" do
319
+ class UnprotectedUser < ActiveRecord::Base
320
+ set_table_name :users
321
+ acts_as_audited :protect => false
322
+ attr_accessible :name, :username, :password
323
+ end
324
+ should "not raise error when attr_accessible is set and protected is false" do
325
+ lambda{
326
+ UnprotectedUser.new(:name => 'NO FAIL!')
327
+ }.should_not raise_error(RuntimeError)
328
+ end
329
+
330
+ class AccessibleUser < ActiveRecord::Base
331
+ set_table_name :users
332
+ attr_accessible :name, :username, :password # declare attr_accessible before calling aaa
333
+ acts_as_audited
334
+ end
335
+ should "not raise an error when attr_accessible is declared before acts_as_audited" do
336
+ lambda{
337
+ AccessibleUser.new(:name => 'NO FAIL!')
338
+ }.should_not raise_error
339
+ end
340
+ end
341
+
342
+ context "audit as" do
343
+ setup do
344
+ @user = User.create :name => 'Testing'
345
+ end
346
+
347
+ should "record user objects" do
348
+ Company.audit_as( @user ) do
349
+ company = Company.create :name => 'The auditors'
350
+ company.name = 'The Auditors'
351
+ company.save
352
+
353
+ company.audits.each do |audit|
354
+ audit.user.should == @user
355
+ end
356
+ end
357
+ end
358
+
359
+ should "record usernames" do
360
+ Company.audit_as( @user.name ) do
361
+ company = Company.create :name => 'The auditors'
362
+ company.name = 'The Auditors, Inc'
363
+ company.save
364
+
365
+ company.audits.each do |audit|
366
+ audit.username.should == @user.name
367
+ end
368
+ end
369
+ end
370
+ end
371
+
372
+ end
373
+ end
374
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ class AuditsController < ActionController::Base
4
+ def audit
5
+ @company = Company.create
6
+ render :nothing => true
7
+ end
8
+
9
+ def update_user
10
+ current_user.update_attributes({:password => 'foo'})
11
+ render :nothing => true
12
+ end
13
+
14
+ private
15
+ attr_accessor :current_user
16
+ end
17
+ AuditsController.view_paths = [File.dirname(__FILE__)]
18
+ ActionController::Routing::Routes.draw {|m| m.connect ':controller/:action/:id' }
19
+
20
+ class AuditsControllerTest < ActionController::TestCase
21
+ should "audit user" do
22
+ user = @controller.send(:current_user=, create_user)
23
+ lambda { post :audit }.should change { Audit.count }
24
+ assigns(:company).audits.last.user.should == user
25
+ end
26
+
27
+ should "not save blank audits" do
28
+ user = @controller.send(:current_user=, create_user)
29
+ lambda { post :update_user }.should_not change { Audit.count }
30
+ end
31
+ end