paper_trail 1.4.0 → 17.0.0

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.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/lib/generators/paper_trail/install/USAGE +31 -0
  3. data/lib/generators/paper_trail/install/install_generator.rb +101 -0
  4. data/lib/generators/paper_trail/install/templates/add_object_changes_to_versions.rb.erb +12 -0
  5. data/lib/generators/paper_trail/install/templates/create_versions.rb.erb +41 -0
  6. data/lib/generators/paper_trail/migration_generator.rb +65 -0
  7. data/lib/generators/paper_trail/update_item_subtype/USAGE +4 -0
  8. data/lib/generators/paper_trail/update_item_subtype/templates/update_versions_for_item_subtype.rb.erb +86 -0
  9. data/lib/generators/paper_trail/update_item_subtype/update_item_subtype_generator.rb +40 -0
  10. data/lib/paper_trail/attribute_serializers/README.md +10 -0
  11. data/lib/paper_trail/attribute_serializers/attribute_serializer_factory.rb +41 -0
  12. data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +51 -0
  13. data/lib/paper_trail/attribute_serializers/object_attribute.rb +48 -0
  14. data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +51 -0
  15. data/lib/paper_trail/cleaner.rb +60 -0
  16. data/lib/paper_trail/compatibility.rb +51 -0
  17. data/lib/paper_trail/config.rb +41 -0
  18. data/lib/paper_trail/errors.rb +33 -0
  19. data/lib/paper_trail/events/base.rb +343 -0
  20. data/lib/paper_trail/events/create.rb +32 -0
  21. data/lib/paper_trail/events/destroy.rb +42 -0
  22. data/lib/paper_trail/events/update.rb +76 -0
  23. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +16 -0
  24. data/lib/paper_trail/frameworks/active_record.rb +12 -0
  25. data/lib/paper_trail/frameworks/cucumber.rb +33 -0
  26. data/lib/paper_trail/frameworks/rails/controller.rb +103 -0
  27. data/lib/paper_trail/frameworks/rails/railtie.rb +34 -0
  28. data/lib/paper_trail/frameworks/rails.rb +3 -0
  29. data/lib/paper_trail/frameworks/rspec/helpers.rb +29 -0
  30. data/lib/paper_trail/frameworks/rspec.rb +42 -0
  31. data/lib/paper_trail/has_paper_trail.rb +79 -82
  32. data/lib/paper_trail/model_config.rb +257 -0
  33. data/lib/paper_trail/queries/versions/where_attribute_changes.rb +50 -0
  34. data/lib/paper_trail/queries/versions/where_object.rb +65 -0
  35. data/lib/paper_trail/queries/versions/where_object_changes.rb +70 -0
  36. data/lib/paper_trail/queries/versions/where_object_changes_from.rb +57 -0
  37. data/lib/paper_trail/queries/versions/where_object_changes_to.rb +57 -0
  38. data/lib/paper_trail/record_history.rb +51 -0
  39. data/lib/paper_trail/record_trail.rb +342 -0
  40. data/lib/paper_trail/reifier.rb +147 -0
  41. data/lib/paper_trail/request.rb +163 -0
  42. data/lib/paper_trail/serializers/json.rb +36 -0
  43. data/lib/paper_trail/serializers/yaml.rb +68 -0
  44. data/lib/paper_trail/type_serializers/postgres_array_serializer.rb +35 -0
  45. data/lib/paper_trail/version_concern.rb +406 -0
  46. data/lib/paper_trail/version_number.rb +23 -0
  47. data/lib/paper_trail.rb +128 -19
  48. metadata +444 -70
  49. data/.gitignore +0 -3
  50. data/README.md +0 -225
  51. data/Rakefile +0 -50
  52. data/VERSION +0 -1
  53. data/generators/paper_trail/USAGE +0 -2
  54. data/generators/paper_trail/paper_trail_generator.rb +0 -9
  55. data/generators/paper_trail/templates/create_versions.rb +0 -18
  56. data/init.rb +0 -1
  57. data/install.rb +0 -1
  58. data/lib/paper_trail/version.rb +0 -59
  59. data/paper_trail.gemspec +0 -67
  60. data/rails/init.rb +0 -1
  61. data/tasks/paper_trail_tasks.rake +0 -0
  62. data/test/database.yml +0 -18
  63. data/test/paper_trail_controller_test.rb +0 -70
  64. data/test/paper_trail_model_test.rb +0 -448
  65. data/test/paper_trail_schema_test.rb +0 -15
  66. data/test/schema.rb +0 -48
  67. data/test/schema_change.rb +0 -3
  68. data/test/test_helper.rb +0 -43
  69. data/uninstall.rb +0 -1
  70. /data/{MIT-LICENSE → LICENSE} +0 -0
@@ -1,448 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper.rb'
2
-
3
- class Widget < ActiveRecord::Base
4
- has_paper_trail
5
- has_one :wotsit
6
- has_many :fluxors, :order => :name
7
- end
8
-
9
- class FooWidget < Widget
10
- end
11
-
12
- class Wotsit < ActiveRecord::Base
13
- belongs_to :widget
14
- end
15
-
16
- class Fluxor < ActiveRecord::Base
17
- belongs_to :widget
18
- end
19
-
20
- class Article < ActiveRecord::Base
21
- has_paper_trail :ignore => [:title],
22
- :meta => {:answer => 42,
23
- :question => Proc.new { "31 + 11 = #{31 + 11}" },
24
- :article_id => Proc.new { |article| article.id } }
25
- end
26
-
27
-
28
- class HasPaperTrailModelTest < Test::Unit::TestCase
29
- load_schema
30
-
31
- context 'A record' do
32
- setup { @article = Article.create }
33
-
34
- context 'which updates an ignored column' do
35
- setup { @article.update_attributes :title => 'My first title' }
36
- should_not_change('the number of versions') { Version.count }
37
- end
38
-
39
- context 'which updates an ignored column and a non-ignored column' do
40
- setup { @article.update_attributes :title => 'My first title', :content => 'Some text here.' }
41
- should_change('the number of versions', :by => 1) { Version.count }
42
- end
43
- end
44
-
45
-
46
- context 'A new record' do
47
- setup { @widget = Widget.new }
48
-
49
- should 'not have any previous versions' do
50
- assert_equal [], @widget.versions
51
- end
52
-
53
-
54
- context 'which is then created' do
55
- setup { @widget.update_attributes :name => 'Henry' }
56
-
57
- should 'have one previous version' do
58
- assert_equal 1, @widget.versions.length
59
- end
60
-
61
- should 'be nil in its previous version' do
62
- assert_nil @widget.versions.first.object
63
- assert_nil @widget.versions.first.reify
64
- end
65
-
66
- should 'record the correct event' do
67
- assert_match /create/i, @widget.versions.first.event
68
- end
69
-
70
-
71
- context 'and then updated without any changes' do
72
- setup { @widget.save }
73
-
74
- should 'not have a new version' do
75
- assert_equal 1, @widget.versions.length
76
- end
77
- end
78
-
79
-
80
- context 'and then updated with changes' do
81
- setup { @widget.update_attributes :name => 'Harry' }
82
-
83
- should 'have two previous versions' do
84
- assert_equal 2, @widget.versions.length
85
- end
86
-
87
- should 'be available in its previous version' do
88
- assert_equal 'Harry', @widget.name
89
- assert_not_nil @widget.versions.last.object
90
- widget = @widget.versions.last.reify
91
- assert_equal 'Henry', widget.name
92
- assert_equal 'Harry', @widget.name
93
- end
94
-
95
- should 'have the same ID in its previous version' do
96
- assert_equal @widget.id, @widget.versions.last.reify.id
97
- end
98
-
99
- should 'record the correct event' do
100
- assert_match /update/i, @widget.versions.last.event
101
- end
102
-
103
-
104
- context 'and has one associated object' do
105
- setup do
106
- @wotsit = @widget.create_wotsit :name => 'John'
107
- @reified_widget = @widget.versions.last.reify
108
- end
109
-
110
- should 'copy the has_one association when reifying' do
111
- assert_equal @wotsit, @reified_widget.wotsit
112
- end
113
- end
114
-
115
-
116
- context 'and has many associated objects' do
117
- setup do
118
- @f0 = @widget.fluxors.create :name => 'f-zero'
119
- @f1 = @widget.fluxors.create :name => 'f-one'
120
- @reified_widget = @widget.versions.last.reify
121
- end
122
-
123
- should 'copy the has_many associations when reifying' do
124
- assert_equal @widget.fluxors.length, @reified_widget.fluxors.length
125
- assert_same_elements @widget.fluxors, @reified_widget.fluxors
126
-
127
- assert_equal @widget.versions.length, @reified_widget.versions.length
128
- assert_same_elements @widget.versions, @reified_widget.versions
129
- end
130
- end
131
-
132
-
133
- context 'and then destroyed' do
134
- setup do
135
- @fluxor = @widget.fluxors.create :name => 'flux'
136
- @widget.destroy
137
- @reified_widget = @widget.versions.last.reify
138
- end
139
-
140
- should 'record the correct event' do
141
- assert_match /destroy/i, @widget.versions.last.event
142
- end
143
-
144
- should 'have three previous versions' do
145
- assert_equal 3, @widget.versions.length
146
- end
147
-
148
- should 'be available in its previous version' do
149
- assert_equal @widget.id, @reified_widget.id
150
- assert_equal @widget.attributes, @reified_widget.attributes
151
- end
152
-
153
- should 'be re-creatable from its previous version' do
154
- assert @reified_widget.save
155
- end
156
-
157
- should 'restore its associations on its previous version' do
158
- @reified_widget.save
159
- assert_equal 1, @reified_widget.fluxors.length
160
- end
161
- end
162
- end
163
- end
164
- end
165
-
166
-
167
- # Test the serialisation and deserialisation.
168
- # TODO: binary
169
- context "A record's papertrail" do
170
- setup do
171
- @date_time = DateTime.now.utc
172
- @time = Time.now
173
- @date = Date.new 2009, 5, 29
174
- @widget = Widget.create :name => 'Warble',
175
- :a_text => 'The quick brown fox',
176
- :an_integer => 42,
177
- :a_float => 153.01,
178
- :a_decimal => 2.71828,
179
- :a_datetime => @date_time,
180
- :a_time => @time,
181
- :a_date => @date,
182
- :a_boolean => true
183
-
184
- @widget.update_attributes :name => nil,
185
- :a_text => nil,
186
- :an_integer => nil,
187
- :a_float => nil,
188
- :a_decimal => nil,
189
- :a_datetime => nil,
190
- :a_time => nil,
191
- :a_date => nil,
192
- :a_boolean => false
193
- @previous = @widget.versions.last.reify
194
- end
195
-
196
- should 'handle strings' do
197
- assert_equal 'Warble', @previous.name
198
- end
199
-
200
- should 'handle text' do
201
- assert_equal 'The quick brown fox', @previous.a_text
202
- end
203
-
204
- should 'handle integers' do
205
- assert_equal 42, @previous.an_integer
206
- end
207
-
208
- should 'handle floats' do
209
- assert_in_delta 153.01, @previous.a_float, 0.001
210
- end
211
-
212
- should 'handle decimals' do
213
- assert_in_delta 2.71828, @previous.a_decimal, 0.00001
214
- end
215
-
216
- should 'handle datetimes' do
217
- # Is there a better way to test equality of two datetimes?
218
- format = '%a, %d %b %Y %H:%M:%S %z' # :rfc822
219
- assert_equal @date_time.utc.strftime(format), @previous.a_datetime.utc.strftime(format)
220
- end
221
-
222
- should 'handle times' do
223
- assert_equal @time, @previous.a_time
224
- end
225
-
226
- should 'handle dates' do
227
- assert_equal @date, @previous.a_date
228
- end
229
-
230
- should 'handle booleans' do
231
- assert @previous.a_boolean
232
- end
233
-
234
-
235
- context "after a column is removed from the record's schema" do
236
- setup do
237
- change_schema
238
- Widget.reset_column_information
239
- assert_raise(NoMethodError) { Widget.new.sacrificial_column }
240
- @last = @widget.versions.last
241
- end
242
-
243
- should 'reify previous version' do
244
- assert_kind_of Widget, @last.reify
245
- end
246
-
247
- should 'restore all forward-compatible attributes' do
248
- format = '%a, %d %b %Y %H:%M:%S %z' # :rfc822
249
- assert_equal 'Warble', @last.reify.name
250
- assert_equal 'The quick brown fox', @last.reify.a_text
251
- assert_equal 42, @last.reify.an_integer
252
- assert_in_delta 153.01, @last.reify.a_float, 0.001
253
- assert_in_delta 2.71828, @last.reify.a_decimal, 0.00001
254
- assert_equal @date_time.utc.strftime(format), @last.reify.a_datetime.utc.strftime(format)
255
- assert_equal @time, @last.reify.a_time
256
- assert_equal @date, @last.reify.a_date
257
- assert @last.reify.a_boolean
258
- end
259
- end
260
- end
261
-
262
-
263
- context 'A record' do
264
- setup { @widget = Widget.create :name => 'Zaphod' }
265
-
266
- context 'with its paper trail turned off' do
267
- setup do
268
- Widget.paper_trail_off
269
- @count = @widget.versions.length
270
- end
271
-
272
- teardown { Widget.paper_trail_on }
273
-
274
- context 'when updated' do
275
- setup { @widget.update_attributes :name => 'Beeblebrox' }
276
-
277
- should 'not add to its trail' do
278
- assert_equal @count, @widget.versions.length
279
- end
280
- end
281
-
282
- context 'and then its paper trail turned on' do
283
- setup { Widget.paper_trail_on }
284
-
285
- context 'when updated' do
286
- setup { @widget.update_attributes :name => 'Ford' }
287
-
288
- should 'add to its trail' do
289
- assert_equal @count + 1, @widget.versions.length
290
- end
291
- end
292
- end
293
- end
294
- end
295
-
296
-
297
- context 'A papertrail with somebody making changes' do
298
- setup do
299
- PaperTrail.whodunnit = 'Colonel Mustard'
300
- @widget = Widget.new :name => 'Fidget'
301
- end
302
-
303
- context 'when a record is created' do
304
- setup { @widget.save }
305
-
306
- should 'track who made the change' do
307
- assert_equal 'Colonel Mustard', @widget.versions.last.whodunnit
308
- end
309
-
310
- context 'when a record is updated' do
311
- setup { @widget.update_attributes :name => 'Rivet' }
312
-
313
- should 'track who made the change' do
314
- assert_equal 'Colonel Mustard', @widget.versions.last.whodunnit
315
- end
316
-
317
- context 'when a record is destroyed' do
318
- setup { @widget.destroy }
319
-
320
- should 'track who made the change' do
321
- assert_equal 'Colonel Mustard', @widget.versions.last.whodunnit
322
- end
323
- end
324
- end
325
- end
326
- end
327
-
328
-
329
- context 'A subclass' do
330
- setup do
331
- @foo = FooWidget.create
332
- @foo.update_attributes :name => 'Fooey'
333
- end
334
-
335
- should 'reify with the correct type' do
336
- thing = @foo.versions.last.reify
337
- assert_kind_of FooWidget, thing
338
- end
339
-
340
-
341
- context 'when destroyed' do
342
- setup { @foo.destroy }
343
-
344
- should 'reify with the correct type' do
345
- thing = @foo.versions.last.reify
346
- assert_kind_of FooWidget, thing
347
- end
348
- end
349
- end
350
-
351
-
352
- context 'An item with versions' do
353
- setup do
354
- @widget = Widget.create :name => 'Widget'
355
- @widget.update_attributes :name => 'Fidget'
356
- @widget.update_attributes :name => 'Digit'
357
- end
358
-
359
- context 'on the first version' do
360
- setup { @version = @widget.versions.first }
361
-
362
- should 'have a nil previous version' do
363
- assert_nil @version.previous
364
- end
365
-
366
- should 'return the next version' do
367
- assert_equal @widget.versions[1], @version.next
368
- end
369
-
370
- should 'return the correct index' do
371
- assert_equal 0, @version.index
372
- end
373
- end
374
-
375
- context 'on the last version' do
376
- setup { @version = @widget.versions.last }
377
-
378
- should 'return the previous version' do
379
- assert_equal @widget.versions[@widget.versions.length - 2], @version.previous
380
- end
381
-
382
- should 'have a nil next version' do
383
- assert_nil @version.next
384
- end
385
-
386
- should 'return the correct index' do
387
- assert_equal @widget.versions.length - 1, @version.index
388
- end
389
- end
390
- end
391
-
392
-
393
- context 'An item' do
394
- setup { @article = Article.new }
395
-
396
- context 'which is created' do
397
- setup { @article.save }
398
-
399
- should 'store fixed meta data' do
400
- assert_equal 42, @article.versions.last.answer
401
- end
402
-
403
- should 'store dynamic meta data which is independent of the item' do
404
- assert_equal '31 + 11 = 42', @article.versions.last.question
405
- end
406
-
407
- should 'store dynamic meta data which depends on the item' do
408
- assert_equal @article.id, @article.versions.last.article_id
409
- end
410
-
411
-
412
- context 'and updated' do
413
- setup { @article.update_attributes! :content => 'Better text.' }
414
-
415
- should 'store fixed meta data' do
416
- assert_equal 42, @article.versions.last.answer
417
- end
418
-
419
- should 'store dynamic meta data which is independent of the item' do
420
- assert_equal '31 + 11 = 42', @article.versions.last.question
421
- end
422
-
423
- should 'store dynamic meta data which depends on the item' do
424
- assert_equal @article.id, @article.versions.last.article_id
425
- end
426
- end
427
-
428
-
429
- context 'and destroyd' do
430
- setup { @article.destroy }
431
-
432
- should 'store fixed meta data' do
433
- assert_equal 42, @article.versions.last.answer
434
- end
435
-
436
- should 'store dynamic meta data which is independent of the item' do
437
- assert_equal '31 + 11 = 42', @article.versions.last.question
438
- end
439
-
440
- should 'store dynamic meta data which depends on the item' do
441
- assert_equal @article.id, @article.versions.last.article_id
442
- end
443
-
444
- end
445
- end
446
- end
447
-
448
- end
@@ -1,15 +0,0 @@
1
- require 'test_helper'
2
-
3
- class PaperTrailSchemaTest < ActiveSupport::TestCase
4
- def setup
5
- load_schema
6
- end
7
-
8
- def test_schema_has_loaded_correctly
9
- assert_equal [], Widget.all
10
- assert_equal [], Version.all
11
- assert_equal [], Wotsit.all
12
- assert_equal [], Fluxor.all
13
- assert_equal [], Article.all
14
- end
15
- end
data/test/schema.rb DELETED
@@ -1,48 +0,0 @@
1
- ActiveRecord::Schema.define(:version => 0) do
2
-
3
- create_table :widgets, :force => true do |t|
4
- t.string :name
5
- t.text :a_text
6
- t.integer :an_integer
7
- t.float :a_float
8
- t.decimal :a_decimal
9
- t.datetime :a_datetime
10
- t.time :a_time
11
- t.date :a_date
12
- t.boolean :a_boolean
13
- t.datetime :created_at, :updated_at
14
- t.string :sacrificial_column
15
- t.string :type
16
- end
17
-
18
- create_table :versions, :force => true do |t|
19
- t.string :item_type, :null => false
20
- t.integer :item_id, :null => false
21
- t.string :event, :null => false
22
- t.string :whodunnit
23
- t.text :object
24
- t.datetime :created_at
25
-
26
- # Metadata columns.
27
- t.integer :answer
28
- t.string :question
29
- t.integer :article_id
30
- end
31
- add_index :versions, [:item_type, :item_id]
32
-
33
- create_table :wotsits, :force => true do |t|
34
- t.integer :widget_id
35
- t.string :name
36
- end
37
-
38
- create_table :fluxors, :force => true do |t|
39
- t.integer :widget_id
40
- t.string :name
41
- end
42
-
43
- create_table :articles, :force => true do |t|
44
- t.integer :title
45
- t.string :content
46
- end
47
-
48
- end
@@ -1,3 +0,0 @@
1
- ActiveRecord::Schema.define do
2
- remove_column :widgets, :sacrificial_column
3
- end
data/test/test_helper.rb DELETED
@@ -1,43 +0,0 @@
1
- require 'test/unit'
2
- RAILS_ROOT = File.join(File.dirname(__FILE__), %w{.. .. .. ..})
3
- $:.unshift(File.join(File.dirname(__FILE__), %w{.. lib}))
4
-
5
- unless defined?(ActiveRecord)
6
- if File.directory? RAILS_ROOT + 'config'
7
- puts 'using config/boot.rb'
8
- ENV['RAILS_ENV'] = 'test'
9
- require File.join(RAILS_ROOT, 'config', 'boot.rb')
10
- else
11
- # simply use installed gems if available
12
- puts 'using rubygems'
13
- require 'rubygems'
14
- gem 'actionpack'; gem 'activerecord'; gem 'activesupport'; gem 'rails'
15
- end
16
-
17
- %w(action_pack action_controller active_record active_support initializer).each {|f| require f}
18
- end
19
- require 'shoulda'
20
- require 'paper_trail'
21
-
22
- def connect_to_database
23
- config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
24
- ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
25
-
26
- db_adapter = ENV['DB'] || 'sqlite3'
27
-
28
- if db_adapter.nil?
29
- raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3."
30
- end
31
-
32
- ActiveRecord::Base.establish_connection(config[db_adapter])
33
- end
34
-
35
- def load_schema
36
- connect_to_database
37
- load(File.dirname(__FILE__) + "/schema.rb")
38
- require File.dirname(__FILE__) + '/../rails/init.rb'
39
- end
40
-
41
- def change_schema
42
- load(File.dirname(__FILE__) + "/schema_change.rb")
43
- end
data/uninstall.rb DELETED
@@ -1 +0,0 @@
1
- # Uninstall hook code here
File without changes