paper_trail 1.5.1 → 1.5.2
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.
- data/README.md +49 -1
- data/VERSION +1 -1
- data/lib/paper_trail/has_paper_trail.rb +7 -2
- data/lib/paper_trail/version.rb +12 -1
- data/paper_trail.gemspec +2 -2
- data/test/paper_trail_model_test.rb +27 -7
- metadata +4 -4
data/README.md
CHANGED
@@ -25,7 +25,7 @@ PaperTrail lets you track changes to your models' data. It's good for auditing
|
|
25
25
|
|
26
26
|
## Rails Version
|
27
27
|
|
28
|
-
Known to work on Rails 2.3. Probably works on Rails 2.2 and 2.1.
|
28
|
+
Reported to work on Rails 3 (though I haven't yet tried myself). Known to work on Rails 2.3. Probably works on Rails 2.2 and 2.1.
|
29
29
|
|
30
30
|
|
31
31
|
## Basic Usage
|
@@ -192,6 +192,25 @@ In a migration or in `script/console` you can set who is responsible like this:
|
|
192
192
|
>> widget.update_attributes :name => 'Wibble'
|
193
193
|
>> widget.versions.last.whodunnit # Andy Stewart
|
194
194
|
|
195
|
+
N.B. A `version`'s `whodunnit` records who changed the object causing the `version` to be stored. Because a `version` stores the object as it looked before the change (see the table above), `whodunnit` returns who stopped the object looking like this -- not who made it look like this. Hence `whodunnit` is aliased as `terminator`.
|
196
|
+
|
197
|
+
To find out who made a `version`'s object look that way, use `version.originator`. And to find out who made a "live" object look like it does, use `originator` on the object.
|
198
|
+
|
199
|
+
>> widget = Widget.find 153 # assume widget has 0 versions
|
200
|
+
>> PaperTrail.whodunnit = 'Alice'
|
201
|
+
>> widget.update_attributes :name => 'Yankee'
|
202
|
+
>> widget.originator # 'Alice'
|
203
|
+
>> PaperTrail.whodunnit = 'Bob'
|
204
|
+
>> widget.update_attributes :name => 'Zulu'
|
205
|
+
>> widget.originator # 'Bob'
|
206
|
+
>> first_version, last_version = widget.versions.first, widget.versions.last
|
207
|
+
>> first_version.whodunnit # 'Alice'
|
208
|
+
>> first_version.originator # nil
|
209
|
+
>> first_version.terminator # 'Alice'
|
210
|
+
>> last_version.whodunnit # 'Bob'
|
211
|
+
>> last_version.originator # 'Alice'
|
212
|
+
>> last_version.terminator # 'Bob'
|
213
|
+
|
195
214
|
|
196
215
|
## Storing metadata
|
197
216
|
|
@@ -220,6 +239,26 @@ You can also store any information you like from your controller. Just override
|
|
220
239
|
Remember to add those extra columns to your `versions` table ;)
|
221
240
|
|
222
241
|
|
242
|
+
## Diffing Versions
|
243
|
+
|
244
|
+
When you're storing every version of an object, as PaperTrail lets you do, you're almost certainly going to want to diff those versions against each other. However I haven't built a diff method into PaperTrail because I think diffing is best left to dedicated libraries, and also it's hard to come up with a diff method to suit all the use cases.
|
245
|
+
|
246
|
+
You might be surprised that PaperTrail doesn't use diffs internally anyway. When I designed PaperTrail I wanted simplicity and robustness so I decided to make each version of an object self-contained. A version stores all of its object's data, not a diff from the previous version.
|
247
|
+
|
248
|
+
So instead here are some specialised diffing libraries which you can use on top of PaperTrail.
|
249
|
+
|
250
|
+
For diffing two strings:
|
251
|
+
|
252
|
+
* [htmldiff](http://github.com/myobie/htmldiff): expects but doesn't require HTML input and produces HTML output. Works very well but slows down significantly on large (e.g. 5,000 word) inputs.
|
253
|
+
* [differ](http://github.com/pvande/differ): expects plain text input and produces plain text/coloured/HTML/any output. Can do character-wise, word-wise, line-wise, or arbitrary-boundary-string-wise diffs. Works very well on non-HTML input.
|
254
|
+
* [diff-lcs](http://github.com/halostatue/ruwiki/tree/master/diff-lcs/trunk): old-school, line-wise diffs.
|
255
|
+
|
256
|
+
For diffing two ActiveRecord objects:
|
257
|
+
|
258
|
+
* [Jeremy Weiskotten's PaperTrail fork](http://github.com/jeremyw/paper_trail/blob/master/lib/paper_trail/has_paper_trail.rb#L151-156): uses ActiveSupport's diff to return an array of hashes of the changes.
|
259
|
+
* [activerecord-diff](http://github.com/tim/activerecord-diff): rather like ActiveRecord::Dirty but also allows you to specify which columns to compare.
|
260
|
+
|
261
|
+
|
223
262
|
## Turning PaperTrail Off/On
|
224
263
|
|
225
264
|
Sometimes you don't want to store changes. Perhaps you are only interested in changes made by your users and don't need to store changes you make yourself in, say, a migration -- or when testing your application.
|
@@ -265,6 +304,15 @@ And then use it in your tests like this:
|
|
265
304
|
end
|
266
305
|
|
267
306
|
|
307
|
+
## Deleting Old Versions
|
308
|
+
|
309
|
+
Over time your `versions` table will grow to an unwieldy size. Because each version is self-contained (see the Diffing section above for more) you can simply delete any records you don't want any more. For example:
|
310
|
+
|
311
|
+
sql> delete from versions where created_at < 2010-06-01;
|
312
|
+
|
313
|
+
>> Version.delete_all ["created_at < ?", 1.week.ago]
|
314
|
+
|
315
|
+
|
268
316
|
## Installation
|
269
317
|
|
270
318
|
1. Install PaperTrail as a gem via your `config/environment.rb`:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.5.
|
1
|
+
1.5.2
|
@@ -78,6 +78,11 @@ module PaperTrail
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
+
# Returns who put the object into its current state.
|
82
|
+
def originator
|
83
|
+
versions.last.try :whodunnit
|
84
|
+
end
|
85
|
+
|
81
86
|
# Returns the object (not a Version) as it was at the given timestamp.
|
82
87
|
def version_at(timestamp)
|
83
88
|
# Short-circuit if the current state is applicable.
|
@@ -87,13 +92,13 @@ module PaperTrail
|
|
87
92
|
# change.
|
88
93
|
version = versions.first :conditions => ['created_at > ?', timestamp],
|
89
94
|
:order => 'created_at ASC'
|
90
|
-
version.reify
|
95
|
+
version.try :reify
|
91
96
|
end
|
92
97
|
|
93
98
|
# Returns the object (not a Version) as it was most recently.
|
94
99
|
def previous_version
|
95
100
|
last_version = version ? version.previous : versions.last
|
96
|
-
last_version.reify
|
101
|
+
last_version.try :reify
|
97
102
|
end
|
98
103
|
|
99
104
|
# Returns the object (not a Version) as it became next.
|
data/lib/paper_trail/version.rb
CHANGED
@@ -40,6 +40,17 @@ class Version < ActiveRecord::Base
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
# Returns who put the item into the state stored in this version.
|
44
|
+
def originator
|
45
|
+
previous.try :whodunnit
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns who changed the item from the state it had in this version.
|
49
|
+
# This is an alias for `whodunnit`.
|
50
|
+
def terminator
|
51
|
+
whodunnit
|
52
|
+
end
|
53
|
+
|
43
54
|
def next
|
44
55
|
Version.first :conditions => ["id > ? AND item_type = ? AND item_id = ?", id, item_type, item_id],
|
45
56
|
:order => 'id ASC'
|
@@ -54,5 +65,5 @@ class Version < ActiveRecord::Base
|
|
54
65
|
Version.all(:conditions => ["item_type = ? AND item_id = ?", item_type, item_id],
|
55
66
|
:order => 'id ASC').index(self)
|
56
67
|
end
|
57
|
-
|
68
|
+
|
58
69
|
end
|
data/paper_trail.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{paper_trail}
|
8
|
-
s.version = "1.5.
|
8
|
+
s.version = "1.5.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Andy Stewart"]
|
12
|
-
s.date = %q{2010-06-
|
12
|
+
s.date = %q{2010-06-28}
|
13
13
|
s.email = %q{boss@airbladesoftware.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"README.md"
|
@@ -310,29 +310,49 @@ class HasPaperTrailModelTest < Test::Unit::TestCase
|
|
310
310
|
|
311
311
|
context 'A papertrail with somebody making changes' do
|
312
312
|
setup do
|
313
|
-
PaperTrail.whodunnit = 'Colonel Mustard'
|
314
313
|
@widget = Widget.new :name => 'Fidget'
|
315
314
|
end
|
316
315
|
|
317
316
|
context 'when a record is created' do
|
318
|
-
setup
|
317
|
+
setup do
|
318
|
+
PaperTrail.whodunnit = 'Alice'
|
319
|
+
@widget.save
|
320
|
+
@version = @widget.versions.last # only 1 version
|
321
|
+
end
|
319
322
|
|
320
323
|
should 'track who made the change' do
|
321
|
-
assert_equal '
|
324
|
+
assert_equal 'Alice', @version.whodunnit
|
325
|
+
assert_nil @version.originator
|
326
|
+
assert_equal 'Alice', @version.terminator
|
327
|
+
assert_equal 'Alice', @widget.originator
|
322
328
|
end
|
323
329
|
|
324
330
|
context 'when a record is updated' do
|
325
|
-
setup
|
331
|
+
setup do
|
332
|
+
PaperTrail.whodunnit = 'Bob'
|
333
|
+
@widget.update_attributes :name => 'Rivet'
|
334
|
+
@version = @widget.versions.last
|
335
|
+
end
|
326
336
|
|
327
337
|
should 'track who made the change' do
|
328
|
-
assert_equal '
|
338
|
+
assert_equal 'Bob', @version.whodunnit
|
339
|
+
assert_equal 'Alice', @version.originator
|
340
|
+
assert_equal 'Bob', @version.terminator
|
341
|
+
assert_equal 'Bob', @widget.originator
|
329
342
|
end
|
330
343
|
|
331
344
|
context 'when a record is destroyed' do
|
332
|
-
setup
|
345
|
+
setup do
|
346
|
+
PaperTrail.whodunnit = 'Charlie'
|
347
|
+
@widget.destroy
|
348
|
+
@version = @widget.versions.last
|
349
|
+
end
|
333
350
|
|
334
351
|
should 'track who made the change' do
|
335
|
-
assert_equal '
|
352
|
+
assert_equal 'Charlie', @version.whodunnit
|
353
|
+
assert_equal 'Bob', @version.originator
|
354
|
+
assert_equal 'Charlie', @version.terminator
|
355
|
+
assert_equal 'Charlie', @widget.originator
|
336
356
|
end
|
337
357
|
end
|
338
358
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paper_trail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 7
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 1.5.
|
9
|
+
- 2
|
10
|
+
version: 1.5.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Andy Stewart
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-06-
|
18
|
+
date: 2010-06-28 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|