paper_trail 3.0.1 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +12 -1
- data/CHANGELOG.md +20 -1
- data/README.md +20 -6
- data/Rakefile +13 -1
- data/gemfiles/3.0.gemfile +16 -6
- data/lib/paper_trail.rb +6 -5
- data/lib/paper_trail/cleaner.rb +3 -2
- data/lib/paper_trail/frameworks/rails.rb +6 -5
- data/lib/paper_trail/frameworks/sinatra.rb +6 -1
- data/lib/paper_trail/has_paper_trail.rb +22 -7
- data/lib/paper_trail/version_concern.rb +31 -8
- data/lib/paper_trail/version_number.rb +1 -1
- data/paper_trail.gemspec +6 -1
- data/spec/models/widget_spec.rb +41 -1
- data/spec/requests/articles_spec.rb +15 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/alt_db_init.rb +24 -9
- data/test/dummy/app/controllers/articles_controller.rb +4 -0
- data/test/dummy/config/database.mysql.yml +19 -0
- data/test/dummy/config/database.postgres.yml +15 -0
- data/test/dummy/config/database.sqlite.yml +15 -0
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +1 -1
- data/test/functional/controller_test.rb +4 -5
- data/test/functional/modular_sinatra_test.rb +4 -3
- data/test/functional/sinatra_test.rb +4 -3
- data/test/test_helper.rb +35 -1
- data/test/unit/cleaner_test.rb +45 -6
- data/test/unit/inheritance_column_test.rb +3 -3
- data/test/unit/model_test.rb +13 -4
- data/test/unit/serializer_test.rb +2 -2
- data/test/unit/timestamp_test.rb +1 -2
- data/test/unit/version_test.rb +12 -14
- metadata +54 -8
- data/test/dummy/config/database.yml +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4b0bcf1de1e90e178545aca16201e7f3bf5de2a
|
4
|
+
data.tar.gz: 01b443dae88b5d51479bbca1e788b723f2c37c89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4ca7aa698867e094708d43673e77a29a681674ab3ddceefda21df783167d7f5876e0ea067945978e58615b25fdd7229f27a1630100d881c9da99feb01ee873a
|
7
|
+
data.tar.gz: f01d87966c55fe86b9894d015cf906ef833fe70e67187a920aa20676694ab5a1c64a79182917fbdb6b5a0cd8ea66d457f3d2370862f6ce764af0573530bbb112
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -5,8 +5,18 @@ rvm:
|
|
5
5
|
- 1.8.7
|
6
6
|
- jruby-19mode
|
7
7
|
- jruby-18mode
|
8
|
+
env:
|
9
|
+
- DB=mysql
|
10
|
+
- DB=postgres
|
11
|
+
- DB=sqlite
|
8
12
|
|
9
|
-
|
13
|
+
before_script:
|
14
|
+
- sh -c "if [ \"$DB\" = 'mysql' ]; then mysql -e 'create database paper_trail_test;'; fi"
|
15
|
+
- sh -c "if [ \"$DB\" = 'mysql' ]; then mysql -e 'create database paper_trail_bar; '; fi"
|
16
|
+
- sh -c "if [ \"$DB\" = 'mysql' ]; then mysql -e 'create database paper_trail_foo; '; fi"
|
17
|
+
- sh -c "if [ \"$DB\" = 'postgres' ]; then psql -c 'create database paper_trail_test;' -U postgres; fi"
|
18
|
+
- sh -c "if [ \"$DB\" = 'postgres' ]; then psql -c 'create database paper_trail_bar;' -U postgres; fi"
|
19
|
+
- sh -c "if [ \"$DB\" = 'postgres' ]; then psql -c 'create database paper_trail_foo;' -U postgres; fi"
|
10
20
|
|
11
21
|
gemfile:
|
12
22
|
- Gemfile
|
@@ -19,3 +29,4 @@ matrix:
|
|
19
29
|
gemfile: Gemfile
|
20
30
|
- rvm: 1.8.7
|
21
31
|
gemfile: Gemfile
|
32
|
+
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
## 3.0.2
|
2
|
+
|
3
|
+
- [#357](https://github.com/airblade/paper_trail/issues/357) - If a `Version` instance is reified and then persisted at that state,
|
4
|
+
it's timestamp attributes for update should still get `touch`ed.
|
5
|
+
- [#351](https://github.com/airblade/paper_trail/pull/351) / [#352](https://github.com/airblade/paper_trail/pull/352) -
|
6
|
+
`PaperTrail::Rails::Controller` should hook into all controller types, and should not get loaded unless `ActionController` is.
|
7
|
+
- [#346](https://github.com/airblade/paper_trail/pull/346) - `user_for_paper_trail` method should accommodate different types
|
8
|
+
for return values from `current_user` method.
|
9
|
+
- [#344](https://github.com/airblade/paper_trail/pull/344) - Gem is now tested against `MySQL` and `PostgreSQL` in addition to `SQLite`.
|
10
|
+
- [#317](https://github.com/airblade/paper_trail/issues/317) / [#314](https://github.com/airblade/paper_trail/issues/314) -
|
11
|
+
`versions` should default to ordering via the primary key if it is an integer to avoid timestamp comparison issues.
|
12
|
+
- `PaperTrail::Cleaner.clean_versions!` should group versions by `PaperTrail.timestamp_field` when deciding which ones to
|
13
|
+
keep / destroy, instead of always grouping by the `created_at` field.
|
14
|
+
- If a `Version` instance is reified and then persisted at that state, it's source version
|
15
|
+
(`model_instance#version_association_name`, usually `model_instance#version`) will get cleared since persisting it causes it to
|
16
|
+
become the live instance.
|
17
|
+
- If `destroy` actions are tracked for a versioned model, invoking `destroy` on the model will cause the corresponding version that
|
18
|
+
gets generated to be assigned as the source version (`model_instance#version_association_name`, usually `model_instance#version`).
|
19
|
+
|
1
20
|
## 3.0.1
|
2
21
|
|
3
22
|
- [#340](https://github.com/airblade/paper_trail/issues/340) - Prevent potential error encountered when using the `InstallGenerator`
|
@@ -32,7 +51,7 @@
|
|
32
51
|
- [#281](https://github.com/airblade/paper_trail/issues/281) - `Rails::Controller` helper will return `false` for the
|
33
52
|
`paper_trail_enabled_for_controller` method if `PaperTrail.enabled? == false`.
|
34
53
|
- [#280](https://github.com/airblade/paper_trail/pull/280) - Don't track virtual timestamp attributes.
|
35
|
-
- [#278](https://github.com/airblade/paper_trail/issues/278)/[#272](https://github.com/airblade/paper_trail/issues/272) -
|
54
|
+
- [#278](https://github.com/airblade/paper_trail/issues/278) / [#272](https://github.com/airblade/paper_trail/issues/272) -
|
36
55
|
Make RSpec and Cucumber helpers usable with [Spork](https://github.com/sporkrb/spork) and [Zeus](https://github.com/burke/zeus).
|
37
56
|
- [#273](https://github.com/airblade/paper_trail/pull/273) - Make the `only` and `ignore` options accept `Hash` arguments;
|
38
57
|
allows for conditional tracking.
|
data/README.md
CHANGED
@@ -42,7 +42,7 @@ The Rails 2.3 code is on the [`rails2`](https://github.com/airblade/paper_trail/
|
|
42
42
|
|
43
43
|
1. Add `PaperTrail` to your `Gemfile`.
|
44
44
|
|
45
|
-
`gem 'paper_trail', '~> 3.0.
|
45
|
+
`gem 'paper_trail', '~> 3.0.2'`
|
46
46
|
|
47
47
|
2. Generate a migration which will add a `versions` table to your database.
|
48
48
|
|
@@ -64,7 +64,7 @@ your applications `ActiveRecord` connection in a manner similar to the way `Rail
|
|
64
64
|
|
65
65
|
1. Add `PaperTrail` to your `Gemfile`.
|
66
66
|
|
67
|
-
`gem 'paper_trail', '~> 3.0.
|
67
|
+
`gem 'paper_trail', '~> 3.0.2'`
|
68
68
|
|
69
69
|
2. Generate a migration to add a `versions` table to your database.
|
70
70
|
|
@@ -889,7 +889,7 @@ A valid serializer is a `module` (or `class`) that defines a `load` and `dump` m
|
|
889
889
|
|
890
890
|
## Limiting the number of versions created per object instance
|
891
891
|
|
892
|
-
If you are
|
892
|
+
If you are wary of your `versions` table growing to an unwieldy size, or just don't care to track more than a certain number of versions per object,
|
893
893
|
there is a configuration option that can be set to cap the number of versions saved per object. Note that this value must be numeric, and it only applies to
|
894
894
|
versions other than `create` events (which will always be preserved if they are stored).
|
895
895
|
|
@@ -1018,11 +1018,23 @@ require 'rspec/rails'
|
|
1018
1018
|
require 'paper_trail/frameworks/rspec'
|
1019
1019
|
```
|
1020
1020
|
|
1021
|
+
## Testing PaperTrail
|
1022
|
+
|
1023
|
+
Paper Trail has facilities to test aganist Postgres, Mysql and SQLite. To switch between DB engines you will need to export the DB Variable for the engine you wish to test aganist.
|
1024
|
+
|
1025
|
+
Though be aware we do not have the abilty to create the db's (except sqlite) for you. You can look at .travis.yml before_script for an example of how to create the db's needed.
|
1026
|
+
|
1027
|
+
```
|
1028
|
+
export DB=postgres
|
1029
|
+
export DB=mysql
|
1030
|
+
export DB=sqlite # this is default
|
1031
|
+
```
|
1032
|
+
|
1021
1033
|
## Articles
|
1022
1034
|
|
1023
|
-
[Using PaperTrail to track stack traces](http://rubyrailsexpert.com/?p=36), T James Corcoran's blog, 1st October 2013.
|
1024
|
-
[RailsCast #255 - Undo with PaperTrail](http://railscasts.com/episodes/255-undo-with-paper-trail), 28th February 2011.
|
1025
|
-
[Keep a Paper Trail with PaperTrail](http://www.linux-mag.com/id/7528), Linux Magazine, 16th September 2009.
|
1035
|
+
* [Using PaperTrail to track stack traces](http://rubyrailsexpert.com/?p=36), T James Corcoran's blog, 1st October 2013.
|
1036
|
+
* [RailsCast #255 - Undo with PaperTrail](http://railscasts.com/episodes/255-undo-with-paper-trail), 28th February 2011.
|
1037
|
+
* [Keep a Paper Trail with PaperTrail](http://www.linux-mag.com/id/7528), Linux Magazine, 16th September 2009.
|
1026
1038
|
|
1027
1039
|
|
1028
1040
|
## Problems
|
@@ -1034,6 +1046,7 @@ Please use GitHub's [issue tracker](http://github.com/airblade/paper_trail/issue
|
|
1034
1046
|
|
1035
1047
|
Many thanks to:
|
1036
1048
|
|
1049
|
+
* [Russell Osborne](https://github.com/rposborne)
|
1037
1050
|
* [Zachery Hostens](http://github.com/zacheryph)
|
1038
1051
|
* [Jeremy Weiskotten](http://github.com/jeremyw)
|
1039
1052
|
* [Phan Le](http://github.com/revo)
|
@@ -1082,6 +1095,7 @@ Many thanks to:
|
|
1082
1095
|
* [Sean Marcia](https://github.com/SeanMarcia)
|
1083
1096
|
* [Chulki Lee](https://github.com/chulkilee)
|
1084
1097
|
* [Lucas Souza](https://github.com/lucasas)
|
1098
|
+
* [Russell Osborne](https://github.com/rposborne)
|
1085
1099
|
|
1086
1100
|
|
1087
1101
|
## Inspirations
|
data/Rakefile
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
3
|
|
4
|
+
desc 'Set a relevant database.yml for testing'
|
5
|
+
task :prepare do
|
6
|
+
ENV["DB"] ||= "sqlite"
|
7
|
+
if RUBY_VERSION.to_f >= 1.9
|
8
|
+
FileUtils.cp "test/dummy/config/database.#{ENV["DB"]}.yml", "test/dummy/config/database.yml"
|
9
|
+
else
|
10
|
+
require 'ftools'
|
11
|
+
File.cp "test/dummy/config/database.#{ENV["DB"]}.yml", "test/dummy/config/database.yml"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
4
16
|
require 'rake/testtask'
|
5
17
|
desc 'Run tests on PaperTrail with Test::Unit.'
|
6
18
|
Rake::TestTask.new(:test) do |t|
|
@@ -15,4 +27,4 @@ desc 'Run PaperTrail specs for the RSpec helper.'
|
|
15
27
|
RSpec::Core::RakeTask.new(:spec)
|
16
28
|
|
17
29
|
desc 'Default: run all available test suites'
|
18
|
-
task :default => [:test, :spec]
|
30
|
+
task :default => [:prepare, :test, :spec]
|
data/gemfiles/3.0.gemfile
CHANGED
@@ -3,7 +3,7 @@ source 'https://rubygems.org'
|
|
3
3
|
gem 'activerecord', '~> 3.0'
|
4
4
|
|
5
5
|
group :development, :test do
|
6
|
-
gem 'rake'
|
6
|
+
gem 'rake', '~> 10.1.1'
|
7
7
|
gem 'shoulda', '~> 3.5'
|
8
8
|
gem 'ffaker', '>= 1.15'
|
9
9
|
|
@@ -14,19 +14,29 @@ group :development, :test do
|
|
14
14
|
gem 'sinatra', '~> 1.0'
|
15
15
|
gem 'rack-test', '>= 0.6'
|
16
16
|
|
17
|
-
# Use sqlite3 gem for regular Ruby
|
18
|
-
gem 'sqlite3', '~> 1.2', :platform => :ruby
|
19
|
-
|
20
17
|
# RSpec testing
|
21
18
|
gem 'rspec-rails', '~> 2.14'
|
22
19
|
gem 'generator_spec'
|
23
20
|
|
21
|
+
# To do proper transactional testing with ActiveSupport::TestCase on MySQL
|
22
|
+
gem 'database_cleaner', '~> 1.2'
|
23
|
+
|
24
|
+
platforms :ruby do
|
25
|
+
gem 'sqlite3', '~> 1.2'
|
26
|
+
gem 'mysql2', '~> 0.3'
|
27
|
+
gem 'pg', '~> 0.17'
|
28
|
+
end
|
29
|
+
|
24
30
|
platforms :jruby, :ruby_18 do
|
25
31
|
# shoulda-matchers > 2.0 is not compatible with Ruby18.
|
26
32
|
# Since we can't specify difference between JRuby 18/19, we need to use shoulda-matchers 1.5 for all JRuby testing.
|
27
33
|
gem 'shoulda-matchers', '~> 1.5'
|
28
34
|
end
|
29
35
|
|
30
|
-
|
31
|
-
|
36
|
+
platforms :jruby do
|
37
|
+
# Use jRuby's sqlite3 adapter for jRuby
|
38
|
+
gem 'activerecord-jdbcsqlite3-adapter', '~> 1.3'
|
39
|
+
gem 'activerecord-jdbcpostgresql-adapter', '~> 1.3'
|
40
|
+
gem 'activerecord-jdbcmysql-adapter', '~> 1.3'
|
41
|
+
end
|
32
42
|
end
|
data/lib/paper_trail.rb
CHANGED
@@ -120,17 +120,18 @@ end
|
|
120
120
|
|
121
121
|
require 'paper_trail/version'
|
122
122
|
|
123
|
+
ActiveSupport.on_load(:active_record) do
|
124
|
+
include PaperTrail::Model
|
125
|
+
end
|
126
|
+
|
123
127
|
# Require frameworks
|
124
|
-
require 'paper_trail/frameworks/rails'
|
125
128
|
require 'paper_trail/frameworks/sinatra'
|
126
129
|
require 'paper_trail/frameworks/rspec' if defined? RSpec
|
127
130
|
require 'paper_trail/frameworks/cucumber' if defined? World
|
128
131
|
|
129
|
-
ActiveSupport.on_load(:active_record) do
|
130
|
-
include PaperTrail::Model
|
131
|
-
end
|
132
|
-
|
133
132
|
if defined?(ActionController)
|
133
|
+
require 'paper_trail/frameworks/rails'
|
134
|
+
|
134
135
|
ActiveSupport.on_load(:action_controller) do
|
135
136
|
include PaperTrail::Rails::Controller
|
136
137
|
end
|
data/lib/paper_trail/cleaner.rb
CHANGED
@@ -12,8 +12,9 @@ module PaperTrail
|
|
12
12
|
def clean_versions!(options = {})
|
13
13
|
options = {:keeping => 1, :date => :all}.merge(options)
|
14
14
|
gather_versions(options[:item_id], options[:date]).each do |item_id, versions|
|
15
|
-
versions.group_by { |v| v.
|
16
|
-
|
15
|
+
versions.group_by { |v| v.send(PaperTrail.timestamp_field).to_date }.each do |date, versions|
|
16
|
+
# remove the number of versions we wish to keep from the collection of versions prior to destruction
|
17
|
+
versions.pop(options[:keeping])
|
17
18
|
versions.map(&:destroy)
|
18
19
|
end
|
19
20
|
end
|
@@ -3,10 +3,8 @@ module PaperTrail
|
|
3
3
|
module Controller
|
4
4
|
|
5
5
|
def self.included(base)
|
6
|
-
|
7
|
-
|
8
|
-
base.before_filter :set_paper_trail_whodunnit, :set_paper_trail_controller_info
|
9
|
-
end
|
6
|
+
base.before_filter :set_paper_trail_enabled_for_controller
|
7
|
+
base.before_filter :set_paper_trail_whodunnit, :set_paper_trail_controller_info
|
10
8
|
end
|
11
9
|
|
12
10
|
protected
|
@@ -17,7 +15,10 @@ module PaperTrail
|
|
17
15
|
# Override this method in your controller to call a different
|
18
16
|
# method, e.g. `current_person`, or anything you like.
|
19
17
|
def user_for_paper_trail
|
20
|
-
|
18
|
+
return unless defined?(current_user)
|
19
|
+
ActiveSupport::VERSION::MAJOR >= 4 ? current_user.try!(:id) : current_user.try(:id)
|
20
|
+
rescue NoMethodError
|
21
|
+
current_user
|
21
22
|
end
|
22
23
|
|
23
24
|
# Returns any information about the controller or request that you
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/object' # provides the `try` method
|
2
|
+
|
1
3
|
module PaperTrail
|
2
4
|
module Sinatra
|
3
5
|
|
@@ -15,7 +17,10 @@ module PaperTrail
|
|
15
17
|
# Override this method in your controller to call a different
|
16
18
|
# method, e.g. `current_person`, or anything you like.
|
17
19
|
def user_for_paper_trail
|
18
|
-
|
20
|
+
return unless defined?(current_user)
|
21
|
+
ActiveSupport::VERSION::MAJOR >= 4 ? current_user.try!(:id) : current_user.try(:id)
|
22
|
+
rescue NoMethodError
|
23
|
+
current_user
|
19
24
|
end
|
20
25
|
|
21
26
|
private
|
@@ -61,18 +61,22 @@ module PaperTrail
|
|
61
61
|
|
62
62
|
if ::ActiveRecord::VERSION::MAJOR >= 4 # `has_many` syntax for specifying order uses a lambda in Rails 4
|
63
63
|
has_many self.versions_association_name,
|
64
|
-
lambda { order(
|
64
|
+
lambda { |model| order(model.version_class_name.constantize.timestamp_sort_order) },
|
65
65
|
:class_name => self.version_class_name, :as => :item
|
66
66
|
else
|
67
67
|
has_many self.versions_association_name,
|
68
68
|
:class_name => self.version_class_name,
|
69
69
|
:as => :item,
|
70
|
-
:order =>
|
70
|
+
:order => self.paper_trail_version_class.timestamp_sort_order
|
71
71
|
end
|
72
72
|
|
73
73
|
options_on = Array(options[:on]) # so that a single symbol can be passed in without wrapping it in an `Array`
|
74
74
|
after_create :record_create, :if => :save_version? if options_on.empty? || options_on.include?(:create)
|
75
|
-
|
75
|
+
if options_on.empty? || options_on.include?(:update)
|
76
|
+
before_save :reset_timestamp_attrs_for_update_if_needed!, :on => :update
|
77
|
+
before_update :record_update, :if => :save_version?
|
78
|
+
after_update :clear_version_instance!
|
79
|
+
end
|
76
80
|
after_destroy :record_destroy, :if => :save_version? if options_on.empty? || options_on.include?(:destroy)
|
77
81
|
end
|
78
82
|
|
@@ -91,7 +95,7 @@ module PaperTrail
|
|
91
95
|
PaperTrail.enabled_for_model(self, true)
|
92
96
|
end
|
93
97
|
|
94
|
-
|
98
|
+
def paper_trail_on
|
95
99
|
warn "DEPRECATED: use `paper_trail_on!` instead of `paper_trail_on`. Support for `paper_trail_on` will be removed in PaperTrail 3.1"
|
96
100
|
self.paper_trail_on!
|
97
101
|
end
|
@@ -165,7 +169,7 @@ module PaperTrail
|
|
165
169
|
# Returns true if this instance is the current, live one;
|
166
170
|
# returns false if this instance came from a previous version.
|
167
171
|
def live?
|
168
|
-
|
172
|
+
source_version.nil?
|
169
173
|
end
|
170
174
|
|
171
175
|
# Returns who put the object into its current state.
|
@@ -177,7 +181,7 @@ module PaperTrail
|
|
177
181
|
def version_at(timestamp, reify_options={})
|
178
182
|
# Because a version stores how its object looked *before* the change,
|
179
183
|
# we need to look for the first version created *after* the timestamp.
|
180
|
-
v = send(self.class.versions_association_name).subsequent(timestamp).first
|
184
|
+
v = send(self.class.versions_association_name).subsequent(timestamp, true).first
|
181
185
|
v ? v.reify(reify_options) : self
|
182
186
|
end
|
183
187
|
|
@@ -271,6 +275,7 @@ module PaperTrail
|
|
271
275
|
:object => self.class.paper_trail_version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs),
|
272
276
|
:whodunnit => PaperTrail.whodunnit
|
273
277
|
}
|
278
|
+
|
274
279
|
if self.class.paper_trail_version_class.column_names.include?('object_changes')
|
275
280
|
data[:object_changes] = self.class.paper_trail_version_class.object_changes_col_is_json? ? changes_for_paper_trail :
|
276
281
|
PaperTrail.serializer.dump(changes_for_paper_trail)
|
@@ -285,6 +290,16 @@ module PaperTrail
|
|
285
290
|
end.tap { |changes| self.class.serialize_attribute_changes(changes) }
|
286
291
|
end
|
287
292
|
|
293
|
+
# Invoked via `after_update` callback for when a previous version is reified and then saved
|
294
|
+
def clear_version_instance!
|
295
|
+
send("#{self.class.version_association_name}=", nil)
|
296
|
+
end
|
297
|
+
|
298
|
+
def reset_timestamp_attrs_for_update_if_needed!
|
299
|
+
return if self.live? # invoked via callback when a user attempts to persist a reified `Version`
|
300
|
+
timestamp_attributes_for_update_in_model.each { |column| send("reset_#{column}!") }
|
301
|
+
end
|
302
|
+
|
288
303
|
def record_destroy
|
289
304
|
if paper_trail_switched_on? and not new_record?
|
290
305
|
object_attrs = object_attrs_for_paper_trail(item_before_change)
|
@@ -295,7 +310,7 @@ module PaperTrail
|
|
295
310
|
:object => self.class.paper_trail_version_class.object_col_is_json? ? object_attrs : PaperTrail.serializer.dump(object_attrs),
|
296
311
|
:whodunnit => PaperTrail.whodunnit
|
297
312
|
}
|
298
|
-
self.class.paper_trail_version_class.create
|
313
|
+
send("#{self.class.version_association_name}=", self.class.paper_trail_version_class.create(merge_metadata(data)))
|
299
314
|
send(self.class.versions_association_name).send :load_target
|
300
315
|
end
|
301
316
|
end
|
@@ -33,22 +33,45 @@ module PaperTrail
|
|
33
33
|
where 'event <> ?', 'create'
|
34
34
|
end
|
35
35
|
|
36
|
-
#
|
37
|
-
|
36
|
+
# Expects `obj` to be an instance of `PaperTrail::Version` by default, but can accept a timestamp if
|
37
|
+
# `timestamp_arg` receives `true`
|
38
|
+
def subsequent(obj, timestamp_arg = false)
|
39
|
+
if timestamp_arg != true && self.primary_key_is_int?
|
40
|
+
return where("#{table_name}.#{self.primary_key} > ?", obj).order("#{table_name}.#{self.primary_key} ASC")
|
41
|
+
end
|
42
|
+
|
38
43
|
obj = obj.send(PaperTrail.timestamp_field) if obj.is_a?(self)
|
39
|
-
where("#{table_name}.#{PaperTrail.timestamp_field} > ?", obj).
|
40
|
-
order("#{table_name}.#{PaperTrail.timestamp_field} ASC")
|
44
|
+
where("#{table_name}.#{PaperTrail.timestamp_field} > ?", obj).order(self.timestamp_sort_order)
|
41
45
|
end
|
42
46
|
|
43
|
-
def preceding(obj)
|
47
|
+
def preceding(obj, timestamp_arg = false)
|
48
|
+
if timestamp_arg != true && self.primary_key_is_int?
|
49
|
+
return where("#{table_name}.#{self.primary_key} < ?", obj).order("#{table_name}.#{self.primary_key} DESC")
|
50
|
+
end
|
51
|
+
|
44
52
|
obj = obj.send(PaperTrail.timestamp_field) if obj.is_a?(self)
|
45
|
-
where("#{table_name}.#{PaperTrail.timestamp_field} < ?", obj).
|
46
|
-
order("#{table_name}.#{PaperTrail.timestamp_field} DESC")
|
53
|
+
where("#{table_name}.#{PaperTrail.timestamp_field} < ?", obj).order(self.timestamp_sort_order('DESC'))
|
47
54
|
end
|
48
55
|
|
56
|
+
|
49
57
|
def between(start_time, end_time)
|
50
58
|
where("#{table_name}.#{PaperTrail.timestamp_field} > ? AND #{table_name}.#{PaperTrail.timestamp_field} < ?",
|
51
|
-
start_time, end_time).order(
|
59
|
+
start_time, end_time).order(self.timestamp_sort_order)
|
60
|
+
end
|
61
|
+
|
62
|
+
# defaults to using the primary key as the secondary sort order if possible
|
63
|
+
def timestamp_sort_order(order = 'ASC')
|
64
|
+
if self.primary_key_is_int?
|
65
|
+
"#{table_name}.#{PaperTrail.timestamp_field} #{order}, #{table_name}.#{self.primary_key} #{order}"
|
66
|
+
else
|
67
|
+
"#{table_name}.#{PaperTrail.timestamp_field} #{order}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def primary_key_is_int?
|
72
|
+
@primary_key_is_int ||= columns_hash[primary_key].type == :integer
|
73
|
+
rescue
|
74
|
+
true
|
52
75
|
end
|
53
76
|
|
54
77
|
# Returns whether the `object` column is using the `json` type supported by PostgreSQL
|
data/paper_trail.gemspec
CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_dependency 'activerecord', ['>= 3.0', '< 5.0']
|
23
23
|
s.add_dependency 'activesupport', ['>= 3.0', '< 5.0']
|
24
24
|
|
25
|
-
s.add_development_dependency 'rake'
|
25
|
+
s.add_development_dependency 'rake', '~> 10.1.1'
|
26
26
|
s.add_development_dependency 'shoulda', '~> 3.5'
|
27
27
|
# s.add_development_dependency 'shoulda-matchers', '~> 1.5' # needed for ActiveRecord < 4
|
28
28
|
s.add_development_dependency 'ffaker', '>= 1.15'
|
@@ -31,11 +31,16 @@ Gem::Specification.new do |s|
|
|
31
31
|
s.add_development_dependency 'rack-test', '>= 0.6'
|
32
32
|
s.add_development_dependency 'rspec-rails', '~> 2.14'
|
33
33
|
s.add_development_dependency 'generator_spec'
|
34
|
+
s.add_development_dependency 'database_cleaner', '~> 1.2'
|
34
35
|
|
35
36
|
# JRuby support for the test ENV
|
36
37
|
unless defined?(JRUBY_VERSION)
|
37
38
|
s.add_development_dependency 'sqlite3', '~> 1.2'
|
39
|
+
s.add_development_dependency 'mysql2', '~> 0.3'
|
40
|
+
s.add_development_dependency 'pg', '~> 0.17'
|
38
41
|
else
|
39
42
|
s.add_development_dependency 'activerecord-jdbcsqlite3-adapter', '~> 1.3'
|
43
|
+
s.add_development_dependency 'activerecord-jdbcpostgresql-adapter', '~> 1.3'
|
44
|
+
s.add_development_dependency 'activerecord-jdbcmysql-adapter', '~> 1.3'
|
40
45
|
end
|
41
46
|
end
|
data/spec/models/widget_spec.rb
CHANGED
@@ -5,7 +5,7 @@ describe Widget do
|
|
5
5
|
it { should be_versioned }
|
6
6
|
end
|
7
7
|
|
8
|
-
let(:widget) { Widget.create :name => 'Bob', :an_integer => 1 }
|
8
|
+
let(:widget) { Widget.create! :name => 'Bob', :an_integer => 1 }
|
9
9
|
|
10
10
|
describe "`versioning` option" do
|
11
11
|
context :enabled, :versioning => true do
|
@@ -21,6 +21,46 @@ describe Widget do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
describe "Callbacks", :versioning => true do
|
25
|
+
describe :before_save do
|
26
|
+
context ':on => :update' do
|
27
|
+
before { widget.update_attributes!(:name => 'Foobar') }
|
28
|
+
|
29
|
+
subject { widget.versions.last.reify }
|
30
|
+
|
31
|
+
it "should reset the value for the timestamp attrs for update so that value gets updated properly" do
|
32
|
+
expect { subject.save! }.to change(subject, :updated_at)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe :after_update do
|
38
|
+
before { widget.update_attributes!(:name => 'Foobar') }
|
39
|
+
|
40
|
+
subject { widget.versions.last.reify }
|
41
|
+
|
42
|
+
it { subject.should_not be_live }
|
43
|
+
|
44
|
+
it "should clear the `versions_association_name` virtual attribute" do
|
45
|
+
subject.save!
|
46
|
+
subject.should be_live
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe :after_destroy do
|
51
|
+
it "should create a version for that event" do
|
52
|
+
expect { widget.destroy }.to change(widget.versions, :count).by(1)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should assign the version into the `versions_association_name`" do
|
56
|
+
widget.version.should be_nil
|
57
|
+
widget.destroy
|
58
|
+
widget.version.should_not be_nil
|
59
|
+
widget.version.should == widget.versions.last
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
24
64
|
describe "Methods" do
|
25
65
|
describe "Instance", :versioning => true do
|
26
66
|
describe :whodunnit do
|
@@ -16,4 +16,19 @@ describe "Articles" do
|
|
16
16
|
PaperTrail.should be_enabled_for_controller
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
with_versioning do
|
21
|
+
let(:article) { Article.last }
|
22
|
+
|
23
|
+
context "`current_user` method returns a `String`" do
|
24
|
+
if RUBY_VERSION.to_f >= 1.9
|
25
|
+
it "should set that value as the `whodunnit`" do
|
26
|
+
expect { post articles_path(valid_params) }.to change(PaperTrail::Version, :count).by(1)
|
27
|
+
article.title.should == 'Doh'
|
28
|
+
PaperTrail.whodunnit.should == 'foobar'
|
29
|
+
article.versions.last.whodunnit.should == 'foobar'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
19
34
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
ENV["RAILS_ENV"] ||= 'test'
|
2
|
+
ENV["DB"] ||= 'sqlite'
|
3
|
+
|
4
|
+
unless File.exists?(File.expand_path('../../test/dummy/config/database.yml', __FILE__))
|
5
|
+
warn "WARNING: No database.yml detected for the dummy app, please run `rake prepare` first"
|
6
|
+
end
|
2
7
|
|
3
8
|
require File.expand_path('../../test/dummy/config/environment', __FILE__)
|
4
9
|
require 'rspec/rails'
|
data/spec/support/alt_db_init.rb
CHANGED
@@ -2,15 +2,21 @@
|
|
2
2
|
# then defines those namespaces, then establishes the sqlite3 connection for the namespaces
|
3
3
|
# to simulate an application with multiple database connections.
|
4
4
|
|
5
|
+
#Load database yaml to use
|
6
|
+
configs = YAML.load_file("#{Rails.root}/config/database.yml")
|
7
|
+
|
8
|
+
#If we are testing with sqlite make it quick
|
5
9
|
db_directory = "#{Rails.root}/db"
|
6
10
|
# setup alternate databases
|
7
|
-
if
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
if ENV["DB"] == "sqlite"
|
12
|
+
if RUBY_VERSION.to_f >= 1.9
|
13
|
+
FileUtils.cp "#{db_directory}/test.sqlite3", "#{db_directory}/test-foo.sqlite3"
|
14
|
+
FileUtils.cp "#{db_directory}/test.sqlite3", "#{db_directory}/test-bar.sqlite3"
|
15
|
+
else
|
16
|
+
require 'ftools'
|
17
|
+
File.cp "#{db_directory}/test.sqlite3", "#{db_directory}/test-foo.sqlite3"
|
18
|
+
File.cp "#{db_directory}/test.sqlite3", "#{db_directory}/test-bar.sqlite3"
|
19
|
+
end
|
14
20
|
end
|
15
21
|
|
16
22
|
module Foo
|
@@ -26,7 +32,11 @@ module Foo
|
|
26
32
|
has_paper_trail :class_name => 'Foo::Version'
|
27
33
|
end
|
28
34
|
end
|
29
|
-
|
35
|
+
|
36
|
+
Foo::Base.configurations = configs
|
37
|
+
Foo::Base.establish_connection(:foo)
|
38
|
+
ActiveRecord::Base.establish_connection(:foo)
|
39
|
+
ActiveRecord::Migrator.migrate File.expand_path("#{db_directory}/migrate/", __FILE__)
|
30
40
|
|
31
41
|
module Bar
|
32
42
|
class Base < ActiveRecord::Base
|
@@ -41,4 +51,9 @@ module Bar
|
|
41
51
|
has_paper_trail :class_name => 'Bar::Version'
|
42
52
|
end
|
43
53
|
end
|
44
|
-
|
54
|
+
|
55
|
+
Bar::Base.configurations = configs
|
56
|
+
Bar::Base.establish_connection(:bar)
|
57
|
+
ActiveRecord::Base.establish_connection(:bar)
|
58
|
+
|
59
|
+
ActiveRecord::Migrator.migrate File.expand_path("#{db_directory}/migrate/", __FILE__)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
test: &test
|
2
|
+
adapter: mysql2
|
3
|
+
encoding: utf8
|
4
|
+
database: paper_trail_test
|
5
|
+
pool: 5
|
6
|
+
username: root
|
7
|
+
password:
|
8
|
+
host: localhost
|
9
|
+
|
10
|
+
# Warning: The database defined as "test" will be erased and
|
11
|
+
# re-generated from your development database when you run "rake".
|
12
|
+
# Do not set this db to the same as development or production.
|
13
|
+
foo:
|
14
|
+
<<: *test
|
15
|
+
database: paper_trail_foo
|
16
|
+
|
17
|
+
bar:
|
18
|
+
<<: *test
|
19
|
+
database: paper_trail_bar
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# SQLite version 3.x
|
2
|
+
# gem install sqlite3-ruby (not necessary on OS X Leopard)
|
3
|
+
test: &test
|
4
|
+
adapter: sqlite3
|
5
|
+
pool: 5
|
6
|
+
timeout: 5000
|
7
|
+
database: db/test.sqlite3
|
8
|
+
|
9
|
+
foo:
|
10
|
+
<<: *test
|
11
|
+
database: db/test-foo.sqlite3
|
12
|
+
|
13
|
+
bar:
|
14
|
+
<<: *test
|
15
|
+
database: db/test-bar.sqlite3
|
@@ -62,11 +62,10 @@ class ControllerTest < ActionController::TestCase
|
|
62
62
|
assert_equal 1, w.versions.length
|
63
63
|
delete :destroy, :id => w.id
|
64
64
|
widget = assigns(:widget)
|
65
|
-
|
66
|
-
assert_equal
|
67
|
-
assert_equal
|
68
|
-
assert_equal
|
69
|
-
assert_equal 'Rails Testing', versions_for_widget.last.user_agent
|
65
|
+
assert_equal 2, widget.versions.length
|
66
|
+
assert_equal '127.0.0.1', widget.versions.last.ip
|
67
|
+
assert_equal 'Rails Testing', widget.versions.last.user_agent
|
68
|
+
assert_equal 153, widget.versions.last.whodunnit.to_i
|
70
69
|
end
|
71
70
|
|
72
71
|
test "controller metadata methods should get evaluated if paper trail is enabled for controller" do
|
@@ -3,7 +3,9 @@ require 'sinatra/base'
|
|
3
3
|
|
4
4
|
# --- Tests for modular `Sinatra::Base` style ----
|
5
5
|
class BaseApp < Sinatra::Base
|
6
|
-
|
6
|
+
configs = YAML.load_file(File.expand_path('../../dummy/config/database.yml', __FILE__))
|
7
|
+
ActiveRecord::Base.configurations = configs
|
8
|
+
ActiveRecord::Base.establish_connection(:test)
|
7
9
|
register PaperTrail::Sinatra
|
8
10
|
|
9
11
|
get '/test' do
|
@@ -27,7 +29,6 @@ class ModularSinatraTest < ActionDispatch::IntegrationTest
|
|
27
29
|
end
|
28
30
|
|
29
31
|
test 'baseline' do
|
30
|
-
assert_nil Widget.first
|
31
32
|
assert_nil Widget.create.versions.first.whodunnit
|
32
33
|
end
|
33
34
|
|
@@ -36,7 +37,7 @@ class ModularSinatraTest < ActionDispatch::IntegrationTest
|
|
36
37
|
should "sets the `user_for_paper_trail` from the `current_user` method" do
|
37
38
|
get '/test'
|
38
39
|
assert_equal 'Hello', last_response.body
|
39
|
-
widget = Widget.
|
40
|
+
widget = Widget.last
|
40
41
|
assert_not_nil widget
|
41
42
|
assert_equal 'foo', widget.name
|
42
43
|
assert_equal 1, widget.versions.size
|
@@ -3,7 +3,9 @@ require 'test_helper'
|
|
3
3
|
|
4
4
|
# --- Tests for non-modular `Sinatra::Application` style ----
|
5
5
|
class Sinatra::Application
|
6
|
-
|
6
|
+
configs = YAML.load_file(File.expand_path('../../dummy/config/database.yml', __FILE__))
|
7
|
+
ActiveRecord::Base.configurations = configs
|
8
|
+
ActiveRecord::Base.establish_connection(:test)
|
7
9
|
register PaperTrail::Sinatra # we shouldn't actually need this line if I'm not mistaken but the tests seem to fail without it ATM
|
8
10
|
|
9
11
|
get '/test' do
|
@@ -28,7 +30,6 @@ class SinatraTest < ActionDispatch::IntegrationTest
|
|
28
30
|
end
|
29
31
|
|
30
32
|
test 'baseline' do
|
31
|
-
assert_nil Widget.first
|
32
33
|
assert_nil Widget.create.versions.first.whodunnit
|
33
34
|
end
|
34
35
|
|
@@ -37,7 +38,7 @@ class SinatraTest < ActionDispatch::IntegrationTest
|
|
37
38
|
should "sets the `user_for_paper_trail` from the `current_user` method" do
|
38
39
|
get '/test'
|
39
40
|
assert_equal 'Hai', last_response.body
|
40
|
-
widget = Widget.
|
41
|
+
widget = Widget.last
|
41
42
|
assert_not_nil widget
|
42
43
|
assert_equal 'bar', widget.name
|
43
44
|
assert_equal 1, widget.versions.size
|
data/test/test_helper.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
|
-
# Configure Rails Envinronment
|
2
1
|
ENV["RAILS_ENV"] = "test"
|
2
|
+
ENV["DB"] ||= "sqlite"
|
3
|
+
|
4
|
+
unless File.exists?(File.expand_path('../../test/dummy/config/database.yml', __FILE__))
|
5
|
+
warn "WARNING: No database.yml detected for the dummy app, please run `rake prepare` first"
|
6
|
+
end
|
7
|
+
|
8
|
+
def using_mysql?
|
9
|
+
@using_mysql ||= ActiveRecord::Base.connection_config[:adapter].to_sym == :mysql2
|
10
|
+
end
|
3
11
|
|
4
12
|
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
5
13
|
require "rails/test_help"
|
6
14
|
require 'shoulda'
|
7
15
|
require 'ffaker'
|
16
|
+
require 'database_cleaner' if using_mysql?
|
8
17
|
|
9
18
|
Rails.backtrace_cleaner.remove_silencers!
|
10
19
|
|
@@ -14,9 +23,18 @@ ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__
|
|
14
23
|
# Load support files
|
15
24
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
16
25
|
|
26
|
+
# DatabaseCleaner is apparently necessary for doing proper transactions within MySQL (ugh)
|
27
|
+
DatabaseCleaner.strategy = :truncation if using_mysql?
|
28
|
+
|
17
29
|
# global setup block resetting Thread.current
|
18
30
|
class ActiveSupport::TestCase
|
31
|
+
if using_mysql?
|
32
|
+
self.use_transactional_fixtures = false
|
33
|
+
setup { DatabaseCleaner.start }
|
34
|
+
end
|
35
|
+
|
19
36
|
teardown do
|
37
|
+
DatabaseCleaner.clean if using_mysql?
|
20
38
|
Thread.current[:paper_trail] = nil
|
21
39
|
end
|
22
40
|
end
|
@@ -32,4 +50,20 @@ def change_schema
|
|
32
50
|
add_column :versions, :custom_created_at, :datetime
|
33
51
|
end
|
34
52
|
ActiveRecord::Migration.verbose = true
|
53
|
+
reset_version_class_column_info!
|
54
|
+
end
|
55
|
+
|
56
|
+
def restore_schema
|
57
|
+
ActiveRecord::Migration.verbose = false
|
58
|
+
ActiveRecord::Schema.define do
|
59
|
+
add_column :widgets, :sacrificial_column, :string
|
60
|
+
remove_column :versions, :custom_created_at
|
61
|
+
end
|
62
|
+
ActiveRecord::Migration.verbose = true
|
63
|
+
reset_version_class_column_info!
|
64
|
+
end
|
65
|
+
|
66
|
+
def reset_version_class_column_info!
|
67
|
+
PaperTrail::Version.connection.schema_cache.clear!
|
68
|
+
PaperTrail::Version.reset_column_information
|
35
69
|
end
|
data/test/unit/cleaner_test.rb
CHANGED
@@ -2,19 +2,21 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class PaperTrailCleanerTest < ActiveSupport::TestCase
|
4
4
|
|
5
|
-
|
5
|
+
def populate_db!
|
6
6
|
@animals = [@animal = Animal.new, @dog = Dog.new, @cat = Cat.new]
|
7
7
|
@animals.each do |animal|
|
8
8
|
3.times { animal.update_attribute(:name, Faker::Name.name) }
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
test 'Baseline' do
|
13
|
-
assert_equal 9, PaperTrail::Version.count
|
14
|
-
@animals.each { |animal| assert_equal 3, animal.versions.size }
|
15
|
-
end
|
16
|
-
|
17
12
|
context '`clean_versions!` method' do
|
13
|
+
setup { self.populate_db! }
|
14
|
+
|
15
|
+
should 'Baseline' do
|
16
|
+
assert_equal 9, PaperTrail::Version.count
|
17
|
+
@animals.each { |animal| assert_equal 3, animal.versions.size }
|
18
|
+
end
|
19
|
+
|
18
20
|
should 'be extended by `PaperTrail` module' do
|
19
21
|
assert_respond_to PaperTrail, :clean_versions!
|
20
22
|
end
|
@@ -140,4 +142,41 @@ class PaperTrailCleanerTest < ActiveSupport::TestCase
|
|
140
142
|
end
|
141
143
|
|
142
144
|
end # clean_versions! method
|
145
|
+
|
146
|
+
context "Custom timestamp field" do
|
147
|
+
setup do
|
148
|
+
change_schema
|
149
|
+
self.populate_db!
|
150
|
+
# now mess with the timestamps
|
151
|
+
@animals.each do |animal|
|
152
|
+
animal.versions.reverse.each_with_index do |version, index|
|
153
|
+
version.update_attribute(:custom_created_at, Time.now.utc + index.days)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
PaperTrail.timestamp_field = :custom_created_at
|
157
|
+
@animals.map { |a| a.versions(true) } # reload the `versions` association for each animal
|
158
|
+
end
|
159
|
+
|
160
|
+
teardown do
|
161
|
+
PaperTrail.timestamp_field = :created_at
|
162
|
+
restore_schema
|
163
|
+
end
|
164
|
+
|
165
|
+
should 'Baseline' do
|
166
|
+
assert_equal 9, PaperTrail::Version.count
|
167
|
+
@animals.each do |animal|
|
168
|
+
assert_equal 3, animal.versions.size
|
169
|
+
animal.versions.each_cons(2) do |a,b|
|
170
|
+
a.created_at.to_date == b.created_at.to_date
|
171
|
+
a.custom_created_at.to_date != b.custom_created_at.to_date
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
should 'group by `PaperTrail.timestamp_field` when seperating the versions by date to clean' do
|
177
|
+
assert_equal 9, PaperTrail::Version.count
|
178
|
+
PaperTrail.clean_versions!
|
179
|
+
assert_equal 9, PaperTrail::Version.count
|
180
|
+
end
|
181
|
+
end
|
143
182
|
end
|
@@ -23,19 +23,19 @@ class InheritanceColumnTest < ActiveSupport::TestCase
|
|
23
23
|
should 'work with custom STI inheritance column' do
|
24
24
|
assert_equal 12, PaperTrail::Version.count
|
25
25
|
assert_equal 4, @animal.versions.count
|
26
|
-
|
26
|
+
assert_nil @animal.versions.first.reify
|
27
27
|
@animal.versions[1..-1].each { |v| assert_equal 'Animal', v.reify.class.name }
|
28
28
|
|
29
29
|
# For some reason `@dog.versions` doesn't include the final `destroy` version.
|
30
30
|
# Neither do `@dog.versions.scoped` nor `@dog.versions(true)` nor `@dog.versions.reload`.
|
31
31
|
dog_versions = PaperTrail::Version.where(:item_id => @dog.id)
|
32
32
|
assert_equal 4, dog_versions.count
|
33
|
-
|
33
|
+
assert_nil dog_versions.first.reify
|
34
34
|
dog_versions[1..-1].each { |v| assert_equal 'Dog', v.reify.class.name }
|
35
35
|
|
36
36
|
cat_versions = PaperTrail::Version.where(:item_id => @cat.id)
|
37
37
|
assert_equal 4, cat_versions.count
|
38
|
-
|
38
|
+
assert_nil cat_versions.first.reify
|
39
39
|
cat_versions[1..-1].each { |v| assert_equal 'Cat', v.reify.class.name }
|
40
40
|
end
|
41
41
|
end
|
data/test/unit/model_test.rb
CHANGED
@@ -213,13 +213,18 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
|
213
213
|
end
|
214
214
|
|
215
215
|
should 'have changes' do
|
216
|
+
|
217
|
+
#TODO Postgres does not appear to pass back ActiveSupport::TimeWithZone,
|
218
|
+
# so chosing the lowest common denominator to test.
|
219
|
+
|
216
220
|
changes = {
|
217
221
|
'name' => [nil, 'Henry'],
|
218
|
-
'created_at' => [nil, @widget.created_at],
|
219
|
-
'updated_at' => [nil, @widget.updated_at],
|
220
|
-
'id' => [nil,
|
222
|
+
'created_at' => [nil, @widget.created_at.to_time.utc],
|
223
|
+
'updated_at' => [nil, @widget.updated_at.to_time.utc],
|
224
|
+
'id' => [nil, @widget.id]
|
221
225
|
}
|
222
226
|
|
227
|
+
assert_equal "Time", @widget.versions.last.changeset['updated_at'][1].class.to_s
|
223
228
|
assert_equal changes, @widget.versions.last.changeset
|
224
229
|
end
|
225
230
|
|
@@ -437,6 +442,10 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
|
437
442
|
@last = @widget.versions.last
|
438
443
|
end
|
439
444
|
|
445
|
+
teardown do
|
446
|
+
restore_schema
|
447
|
+
end
|
448
|
+
|
440
449
|
should 'reify previous version' do
|
441
450
|
assert_kind_of Widget, @last.reify
|
442
451
|
end
|
@@ -933,7 +942,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
|
|
933
942
|
should 'store version on join clear' do
|
934
943
|
@book.authors << @dostoyevsky
|
935
944
|
count = PaperTrail::Version.count
|
936
|
-
@book.authorships(true).
|
945
|
+
@book.authorships(true).destroy_all
|
937
946
|
assert_equal 1, PaperTrail::Version.count - count
|
938
947
|
assert_equal @book, PaperTrail::Version.last.reify.book
|
939
948
|
assert_equal @dostoyevsky, PaperTrail::Version.last.reify.person
|
@@ -65,7 +65,7 @@ class SerializerTest < ActiveSupport::TestCase
|
|
65
65
|
end
|
66
66
|
|
67
67
|
should 'store object_changes' do
|
68
|
-
initial_changeset = {"name" => [nil, "Some text."], "id" => [nil,
|
68
|
+
initial_changeset = {"name" => [nil, "Some text."], "id" => [nil, @fluxor.id]}
|
69
69
|
second_changeset = {"name"=>["Some text.", "Some more text."]}
|
70
70
|
assert_equal initial_changeset, @fluxor.versions[0].changeset
|
71
71
|
assert_equal second_changeset, @fluxor.versions[1].changeset
|
@@ -107,7 +107,7 @@ class SerializerTest < ActiveSupport::TestCase
|
|
107
107
|
end
|
108
108
|
|
109
109
|
should 'store object_changes' do
|
110
|
-
initial_changeset = {"id" => [nil,
|
110
|
+
initial_changeset = {"id" => [nil, @fluxor.id]}
|
111
111
|
second_changeset = {"name"=>[nil, "Some more text."]}
|
112
112
|
assert_equal initial_changeset, @fluxor.versions[0].changeset
|
113
113
|
assert_equal second_changeset, @fluxor.versions[1].changeset
|
data/test/unit/timestamp_test.rb
CHANGED
@@ -5,8 +5,6 @@ class TimestampTest < ActiveSupport::TestCase
|
|
5
5
|
setup do
|
6
6
|
PaperTrail.timestamp_field = :custom_created_at
|
7
7
|
change_schema
|
8
|
-
PaperTrail::Version.connection.schema_cache.clear!
|
9
|
-
PaperTrail::Version.reset_column_information
|
10
8
|
|
11
9
|
Fluxor.instance_eval <<-END
|
12
10
|
has_paper_trail
|
@@ -19,6 +17,7 @@ class TimestampTest < ActiveSupport::TestCase
|
|
19
17
|
|
20
18
|
teardown do
|
21
19
|
PaperTrail.timestamp_field = :created_at
|
20
|
+
restore_schema
|
22
21
|
end
|
23
22
|
|
24
23
|
test 'versions works with custom timestamp field' do
|
data/test/unit/version_test.rb
CHANGED
@@ -7,6 +7,12 @@ class PaperTrail::VersionTest < ActiveSupport::TestCase
|
|
7
7
|
assert PaperTrail::Version.creates.present?
|
8
8
|
end
|
9
9
|
|
10
|
+
teardown do
|
11
|
+
restore_schema
|
12
|
+
Animal.connection.schema_cache.clear!
|
13
|
+
Animal.reset_column_information
|
14
|
+
end
|
15
|
+
|
10
16
|
context "PaperTrail::Version.creates" do
|
11
17
|
should "return only create events" do
|
12
18
|
PaperTrail::Version.creates.each do |version|
|
@@ -59,10 +65,10 @@ class PaperTrail::VersionTest < ActiveSupport::TestCase
|
|
59
65
|
setup { 2.times { @animal.update_attributes(:name => Faker::Lorem.word) } }
|
60
66
|
|
61
67
|
context "receiving a TimeStamp" do
|
62
|
-
should "return all versions that were created before the Timestamp
|
63
|
-
value = PaperTrail::Version.subsequent(1.hour.ago)
|
68
|
+
should "return all versions that were created before the Timestamp" do
|
69
|
+
value = PaperTrail::Version.subsequent(1.hour.ago, true)
|
64
70
|
assert_equal value, @animal.versions.to_a
|
65
|
-
assert_not_nil value.to_sql.match(/ORDER BY versions.created_at ASC
|
71
|
+
assert_not_nil value.to_sql.match(/ORDER BY versions.created_at ASC/)
|
66
72
|
end
|
67
73
|
end
|
68
74
|
|
@@ -70,10 +76,6 @@ class PaperTrail::VersionTest < ActiveSupport::TestCase
|
|
70
76
|
should "grab the Timestamp from the version and use that as the value" do
|
71
77
|
value = PaperTrail::Version.subsequent(@animal.versions.first)
|
72
78
|
assert_equal value, @animal.versions.to_a.tap { |assoc| assoc.shift }
|
73
|
-
# This asssertion can't pass in Ruby18 because the `strftime` method doesn't accept the %6 (milliseconds) command
|
74
|
-
if RUBY_VERSION.to_f >= 1.9 and not defined?(JRUBY_VERSION)
|
75
|
-
assert_not_nil value.to_sql.match(/WHERE \(versions.created_at > '#{@animal.versions.first.send(PaperTrail.timestamp_field).strftime("%F %T.%6N")}'\)/)
|
76
|
-
end
|
77
79
|
end
|
78
80
|
end
|
79
81
|
end
|
@@ -82,10 +84,10 @@ class PaperTrail::VersionTest < ActiveSupport::TestCase
|
|
82
84
|
setup { 2.times { @animal.update_attributes(:name => Faker::Lorem.word) } }
|
83
85
|
|
84
86
|
context "receiving a TimeStamp" do
|
85
|
-
should "return all versions that were created before the Timestamp
|
86
|
-
value = PaperTrail::Version.preceding(
|
87
|
+
should "return all versions that were created before the Timestamp" do
|
88
|
+
value = PaperTrail::Version.preceding(5.seconds.from_now, true)
|
87
89
|
assert_equal value, @animal.versions.reverse
|
88
|
-
assert_not_nil value.to_sql.match(/ORDER BY versions.created_at DESC
|
90
|
+
assert_not_nil value.to_sql.match(/ORDER BY versions.created_at DESC/)
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
@@ -93,10 +95,6 @@ class PaperTrail::VersionTest < ActiveSupport::TestCase
|
|
93
95
|
should "grab the Timestamp from the version and use that as the value" do
|
94
96
|
value = PaperTrail::Version.preceding(@animal.versions.last)
|
95
97
|
assert_equal value, @animal.versions.to_a.tap { |assoc| assoc.pop }.reverse
|
96
|
-
# This asssertion can't pass in Ruby18 because the `strftime` method doesn't accept the %6 (milliseconds) command
|
97
|
-
if RUBY_VERSION.to_f >= 1.9 and not defined?(JRUBY_VERSION)
|
98
|
-
assert_not_nil value.to_sql.match(/WHERE \(versions.created_at < '#{@animal.versions.last.send(PaperTrail.timestamp_field).strftime("%F %T.%6N")}'\)/)
|
99
|
-
end
|
100
98
|
end
|
101
99
|
end
|
102
100
|
end
|
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: 3.0.
|
4
|
+
version: 3.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Stewart
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-05-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -55,16 +55,16 @@ dependencies:
|
|
55
55
|
name: rake
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
|
-
- -
|
58
|
+
- - ~>
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
60
|
+
version: 10.1.1
|
61
61
|
type: :development
|
62
62
|
prerelease: false
|
63
63
|
version_requirements: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
|
-
- -
|
65
|
+
- - ~>
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: 10.1.1
|
68
68
|
- !ruby/object:Gem::Dependency
|
69
69
|
name: shoulda
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
@@ -169,6 +169,20 @@ dependencies:
|
|
169
169
|
- - '>='
|
170
170
|
- !ruby/object:Gem::Version
|
171
171
|
version: '0'
|
172
|
+
- !ruby/object:Gem::Dependency
|
173
|
+
name: database_cleaner
|
174
|
+
requirement: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ~>
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '1.2'
|
179
|
+
type: :development
|
180
|
+
prerelease: false
|
181
|
+
version_requirements: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ~>
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '1.2'
|
172
186
|
- !ruby/object:Gem::Dependency
|
173
187
|
name: sqlite3
|
174
188
|
requirement: !ruby/object:Gem::Requirement
|
@@ -183,6 +197,34 @@ dependencies:
|
|
183
197
|
- - ~>
|
184
198
|
- !ruby/object:Gem::Version
|
185
199
|
version: '1.2'
|
200
|
+
- !ruby/object:Gem::Dependency
|
201
|
+
name: mysql2
|
202
|
+
requirement: !ruby/object:Gem::Requirement
|
203
|
+
requirements:
|
204
|
+
- - ~>
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0.3'
|
207
|
+
type: :development
|
208
|
+
prerelease: false
|
209
|
+
version_requirements: !ruby/object:Gem::Requirement
|
210
|
+
requirements:
|
211
|
+
- - ~>
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '0.3'
|
214
|
+
- !ruby/object:Gem::Dependency
|
215
|
+
name: pg
|
216
|
+
requirement: !ruby/object:Gem::Requirement
|
217
|
+
requirements:
|
218
|
+
- - ~>
|
219
|
+
- !ruby/object:Gem::Version
|
220
|
+
version: '0.17'
|
221
|
+
type: :development
|
222
|
+
prerelease: false
|
223
|
+
version_requirements: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - ~>
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: '0.17'
|
186
228
|
description: Track changes to your models' data. Good for auditing or versioning.
|
187
229
|
email: batkinz@gmail.com
|
188
230
|
executables: []
|
@@ -257,7 +299,9 @@ files:
|
|
257
299
|
- test/dummy/config.ru
|
258
300
|
- test/dummy/config/application.rb
|
259
301
|
- test/dummy/config/boot.rb
|
260
|
-
- test/dummy/config/database.yml
|
302
|
+
- test/dummy/config/database.mysql.yml
|
303
|
+
- test/dummy/config/database.postgres.yml
|
304
|
+
- test/dummy/config/database.sqlite.yml
|
261
305
|
- test/dummy/config/environment.rb
|
262
306
|
- test/dummy/config/environments/development.rb
|
263
307
|
- test/dummy/config/environments/production.rb
|
@@ -367,7 +411,9 @@ test_files:
|
|
367
411
|
- test/dummy/config.ru
|
368
412
|
- test/dummy/config/application.rb
|
369
413
|
- test/dummy/config/boot.rb
|
370
|
-
- test/dummy/config/database.yml
|
414
|
+
- test/dummy/config/database.mysql.yml
|
415
|
+
- test/dummy/config/database.postgres.yml
|
416
|
+
- test/dummy/config/database.sqlite.yml
|
371
417
|
- test/dummy/config/environment.rb
|
372
418
|
- test/dummy/config/environments/development.rb
|
373
419
|
- test/dummy/config/environments/production.rb
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# SQLite version 3.x
|
2
|
-
# gem install sqlite3-ruby (not necessary on OS X Leopard)
|
3
|
-
development:
|
4
|
-
adapter: sqlite3
|
5
|
-
database: db/development.sqlite3
|
6
|
-
pool: 5
|
7
|
-
timeout: 5000
|
8
|
-
|
9
|
-
# Warning: The database defined as "test" will be erased and
|
10
|
-
# re-generated from your development database when you run "rake".
|
11
|
-
# Do not set this db to the same as development or production.
|
12
|
-
test:
|
13
|
-
adapter: sqlite3
|
14
|
-
database: db/test.sqlite3
|
15
|
-
pool: 5
|
16
|
-
timeout: 5000
|
17
|
-
|
18
|
-
production:
|
19
|
-
adapter: sqlite3
|
20
|
-
database: db/production.sqlite3
|
21
|
-
pool: 5
|
22
|
-
timeout: 5000
|