paper_trail 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
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.0
1
+ 1.4.1
data/init.rb CHANGED
@@ -1 +1 @@
1
- # Include hook code here
1
+ require 'paper_trail'
data/install.rb CHANGED
@@ -1 +1 @@
1
- # Install hook code here
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 rakefile, and run the gemspec command
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.0"
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-01-06}
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 File.dirname(__FILE__) + '/test_helper.rb'
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
- @controller = WidgetsController.new
37
- @request = ActionController::TestRequest.new
38
- @response = ActionController::TestResponse.new
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 File.dirname(__FILE__) + '/test_helper.rb'
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 '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
1
+ require 'rubygems'
16
2
 
17
- %w(action_pack action_controller active_record active_support initializer).each {|f| require f}
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
- db_adapter = ENV['DB'] || 'sqlite3'
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
- if db_adapter.nil?
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
- ActiveRecord::Base.establish_connection(config[db_adapter])
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(File.dirname(__FILE__) + "/schema.rb")
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(File.dirname(__FILE__) + "/schema_change.rb")
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.0
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-01-06 00:00:00 +00:00
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