paper_trail 1.4.0 → 1.4.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.
- data/README.md +14 -0
- data/VERSION +1 -1
- data/init.rb +1 -1
- data/install.rb +1 -1
- data/lib/paper_trail/has_paper_trail.rb +13 -1
- data/paper_trail.gemspec +3 -5
- data/test/paper_trail_controller_test.rb +5 -4
- data/test/paper_trail_model_test.rb +44 -3
- data/test/test_helper.rb +24 -30
- metadata +2 -4
- data/rails/init.rb +0 -1
- data/test/database.yml +0 -18
data/README.md
CHANGED
@@ -10,6 +10,7 @@ PaperTrail lets you track changes to your models' data. It's good for auditing
|
|
10
10
|
* Does not store updates which only change attributes you are ignoring.
|
11
11
|
* Allows you to get at every version, including the original, even once destroyed.
|
12
12
|
* Allows you to get at every version even if the schema has since changed.
|
13
|
+
* Allows you to get at the version as of a particular time.
|
13
14
|
* Automatically records who was responsible if your controller has a `current_user` method.
|
14
15
|
* Allows you to set who is responsible at model-level (useful for migrations).
|
15
16
|
* Allows you to store arbitrary metadata with each version (useful for filtering versions).
|
@@ -118,6 +119,13 @@ PaperTrail makes reverting to a previous version easy:
|
|
118
119
|
>> widget = widget.versions.last.reify # the widget as it was before the update
|
119
120
|
>> widget.save # reverted
|
120
121
|
|
122
|
+
Alternatively you can find the version at a given time:
|
123
|
+
|
124
|
+
>> widget = widget.version_at(1.day.ago) # the widget as it was one day ago
|
125
|
+
>> widget.save # reverted
|
126
|
+
|
127
|
+
Note `version_at` gives you the object, not a version, so you don't need to call `reify`.
|
128
|
+
|
121
129
|
Undeleting is just as simple:
|
122
130
|
|
123
131
|
>> widget = Widget.find 42
|
@@ -201,6 +209,11 @@ And on again like this:
|
|
201
209
|
PaperTrail has a thorough suite of tests. Thanks to [Zachery Hostens](http://github.com/zacheryph) for making them able to run standalone, i.e. without needing PaperTrail to be sitting in a Rails app.
|
202
210
|
|
203
211
|
|
212
|
+
## Articles
|
213
|
+
|
214
|
+
[Keep a Paper Trail with PaperTrail](http://www.linux-mag.com/id/7528), Linux Magazine, 16th September 2009.
|
215
|
+
|
216
|
+
|
204
217
|
## Problems
|
205
218
|
|
206
219
|
Please use GitHub's [issue tracker](http://github.com/airblade/paper_trail/issues).
|
@@ -211,6 +224,7 @@ Please use GitHub's [issue tracker](http://github.com/airblade/paper_trail/issue
|
|
211
224
|
Many thanks to:
|
212
225
|
|
213
226
|
* [Zachery Hostens](http://github.com/zacheryph)
|
227
|
+
* [Jeremy Weiskotten](http://github.com/jeremyw)
|
214
228
|
|
215
229
|
|
216
230
|
## Inspirations
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.4.
|
1
|
+
1.4.1
|
data/init.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
require 'paper_trail'
|
data/install.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
puts 'You have chosen wisely.'
|
@@ -19,7 +19,7 @@ module PaperTrail
|
|
19
19
|
|
20
20
|
cattr_accessor :meta
|
21
21
|
self.meta = options[:meta] || {}
|
22
|
-
|
22
|
+
|
23
23
|
cattr_accessor :paper_trail_active
|
24
24
|
self.paper_trail_active = true
|
25
25
|
|
@@ -63,6 +63,18 @@ module PaperTrail
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
# Returns the object (not a Version) as it was at the given timestamp.
|
67
|
+
def version_at(timestamp)
|
68
|
+
# Short-circuit if the current state is applicable.
|
69
|
+
return self if self.updated_at <= timestamp
|
70
|
+
# Look for the first version created after, rather than before, the
|
71
|
+
# timestamp because a version stores how the object looked before the
|
72
|
+
# change.
|
73
|
+
version = versions.first :conditions => ['created_at > ?', timestamp],
|
74
|
+
:order => 'created_at ASC'
|
75
|
+
version.reify if version
|
76
|
+
end
|
77
|
+
|
66
78
|
private
|
67
79
|
|
68
80
|
def merge_metadata(data)
|
data/paper_trail.gemspec
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{paper_trail}
|
8
|
-
s.version = "1.4.
|
8
|
+
s.version = "1.4.1"
|
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-
|
12
|
+
s.date = %q{2010-03-18}
|
13
13
|
s.email = %q{boss@airbladesoftware.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"README.md"
|
@@ -29,9 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
"lib/paper_trail/has_paper_trail.rb",
|
30
30
|
"lib/paper_trail/version.rb",
|
31
31
|
"paper_trail.gemspec",
|
32
|
-
"rails/init.rb",
|
33
32
|
"tasks/paper_trail_tasks.rake",
|
34
|
-
"test/database.yml",
|
35
33
|
"test/paper_trail_controller_test.rb",
|
36
34
|
"test/paper_trail_model_test.rb",
|
37
35
|
"test/paper_trail_schema_test.rb",
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
3
|
class ApplicationController < ActionController::Base
|
4
4
|
def rescue_action(e)
|
@@ -32,10 +32,11 @@ end
|
|
32
32
|
|
33
33
|
|
34
34
|
class PaperTrailControllerTest < ActionController::TestCase #Test::Unit::TestCase
|
35
|
+
tests WidgetsController
|
35
36
|
def setup
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
#@controller = WidgetsController.new
|
38
|
+
#@request = ActionController::TestRequest.new
|
39
|
+
#@response = ActionController::TestResponse.new
|
39
40
|
|
40
41
|
ActionController::Routing::Routes.draw do |map|
|
41
42
|
map.resources :widgets
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
3
|
class Widget < ActiveRecord::Base
|
4
4
|
has_paper_trail
|
@@ -30,7 +30,7 @@ class HasPaperTrailModelTest < Test::Unit::TestCase
|
|
30
30
|
|
31
31
|
context 'A record' do
|
32
32
|
setup { @article = Article.create }
|
33
|
-
|
33
|
+
|
34
34
|
context 'which updates an ignored column' do
|
35
35
|
setup { @article.update_attributes :title => 'My first title' }
|
36
36
|
should_not_change('the number of versions') { Version.count }
|
@@ -100,7 +100,7 @@ class HasPaperTrailModelTest < Test::Unit::TestCase
|
|
100
100
|
assert_match /update/i, @widget.versions.last.event
|
101
101
|
end
|
102
102
|
|
103
|
-
|
103
|
+
|
104
104
|
context 'and has one associated object' do
|
105
105
|
setup do
|
106
106
|
@wotsit = @widget.create_wotsit :name => 'John'
|
@@ -356,6 +356,47 @@ class HasPaperTrailModelTest < Test::Unit::TestCase
|
|
356
356
|
@widget.update_attributes :name => 'Digit'
|
357
357
|
end
|
358
358
|
|
359
|
+
context 'which were created over time' do
|
360
|
+
setup do
|
361
|
+
@created = 2.days.ago
|
362
|
+
@first_update = 1.day.ago
|
363
|
+
@second_update = 1.hour.ago
|
364
|
+
@widget.versions[0].update_attributes :created_at => @created
|
365
|
+
@widget.versions[1].update_attributes :created_at => @first_update
|
366
|
+
@widget.versions[2].update_attributes :created_at => @second_update
|
367
|
+
@widget.update_attribute :updated_at, @second_update
|
368
|
+
end
|
369
|
+
|
370
|
+
should 'return nil for version_at before it was created' do
|
371
|
+
assert_nil @widget.version_at(@created - 1)
|
372
|
+
end
|
373
|
+
|
374
|
+
should 'return how it looked when created for version_at its creation' do
|
375
|
+
assert_equal 'Widget', @widget.version_at(@created).name
|
376
|
+
end
|
377
|
+
|
378
|
+
should "return how it looked when created for version_at just before its first update" do
|
379
|
+
assert_equal 'Widget', @widget.version_at(@first_update - 1).name
|
380
|
+
end
|
381
|
+
|
382
|
+
should "return how it looked when first updated for version_at its first update" do
|
383
|
+
assert_equal 'Fidget', @widget.version_at(@first_update).name
|
384
|
+
end
|
385
|
+
|
386
|
+
should 'return how it looked when first updated for version_at just before its second update' do
|
387
|
+
assert_equal 'Fidget', @widget.version_at(@second_update - 1).name
|
388
|
+
end
|
389
|
+
|
390
|
+
should 'return how it looked when subsequently updated for version_at its second update' do
|
391
|
+
assert_equal 'Digit', @widget.version_at(@second_update).name
|
392
|
+
end
|
393
|
+
|
394
|
+
should 'return the current object for version_at after latest update' do
|
395
|
+
assert_equal 'Digit', @widget.version_at(1.day.from_now).name
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
|
359
400
|
context 'on the first version' do
|
360
401
|
setup { @version = @widget.versions.first }
|
361
402
|
|
data/test/test_helper.rb
CHANGED
@@ -1,43 +1,37 @@
|
|
1
|
-
require '
|
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
|
1
|
+
require 'rubygems'
|
16
2
|
|
17
|
-
|
18
|
-
end
|
3
|
+
require 'test/unit'
|
19
4
|
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
5
|
|
26
|
-
|
6
|
+
require 'active_record'
|
7
|
+
require 'action_controller'
|
8
|
+
require 'action_controller/test_process'
|
9
|
+
require 'active_support'
|
10
|
+
require 'active_support/test_case'
|
27
11
|
|
28
|
-
|
29
|
-
raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3."
|
30
|
-
end
|
12
|
+
require 'lib/paper_trail'
|
31
13
|
|
32
|
-
|
14
|
+
def connect_to_database
|
15
|
+
ActiveRecord::Base.establish_connection(
|
16
|
+
:adapter => "sqlite3",
|
17
|
+
:database => ":memory:"
|
18
|
+
)
|
19
|
+
ActiveRecord::Migration.verbose = false
|
33
20
|
end
|
34
21
|
|
35
22
|
def load_schema
|
36
23
|
connect_to_database
|
37
|
-
load
|
38
|
-
require File.dirname(__FILE__) + '/../rails/init.rb'
|
24
|
+
load File.dirname(__FILE__) + '/schema.rb'
|
39
25
|
end
|
40
26
|
|
41
27
|
def change_schema
|
42
|
-
load
|
28
|
+
load File.dirname(__FILE__) + '/schema_change.rb'
|
29
|
+
end
|
30
|
+
|
31
|
+
class ActiveRecord::Base
|
32
|
+
def logger
|
33
|
+
@logger ||= Logger.new(nil)
|
34
|
+
end
|
43
35
|
end
|
36
|
+
|
37
|
+
load_schema
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paper_trail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Stewart
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-03-18 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -36,9 +36,7 @@ files:
|
|
36
36
|
- lib/paper_trail/has_paper_trail.rb
|
37
37
|
- lib/paper_trail/version.rb
|
38
38
|
- paper_trail.gemspec
|
39
|
-
- rails/init.rb
|
40
39
|
- tasks/paper_trail_tasks.rake
|
41
|
-
- test/database.yml
|
42
40
|
- test/paper_trail_controller_test.rb
|
43
41
|
- test/paper_trail_model_test.rb
|
44
42
|
- test/paper_trail_schema_test.rb
|
data/rails/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'paper_trail'
|
data/test/database.yml
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
sqlite3:
|
2
|
-
adapter: sqlite3
|
3
|
-
database: ":memory:"
|
4
|
-
|
5
|
-
postgresql:
|
6
|
-
adapter: postgresql
|
7
|
-
username: postgres
|
8
|
-
password: postgres
|
9
|
-
database: paper_trail_plugin_test
|
10
|
-
min_messages: ERROR
|
11
|
-
|
12
|
-
mysql:
|
13
|
-
adapter: mysql
|
14
|
-
host: localhost
|
15
|
-
username: andy
|
16
|
-
password:
|
17
|
-
database: paper_trail_plugin_test
|
18
|
-
socket: /tmp/mysql.sock
|