paper_trail 3.0.6 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +5 -0
- data/.rspec +1 -2
- data/.travis.yml +14 -5
- data/CHANGELOG.md +215 -8
- data/CONTRIBUTING.md +84 -0
- data/README.md +922 -502
- data/Rakefile +2 -2
- data/doc/bug_report_template.rb +65 -0
- data/gemfiles/ar3.gemfile +61 -0
- data/lib/generators/paper_trail/install_generator.rb +22 -3
- data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb +6 -1
- data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb +11 -0
- data/lib/generators/paper_trail/templates/create_version_associations.rb +17 -0
- data/lib/generators/paper_trail/templates/create_versions.rb +22 -1
- data/lib/paper_trail.rb +52 -22
- data/lib/paper_trail/attributes_serialization.rb +89 -0
- data/lib/paper_trail/cleaner.rb +32 -15
- data/lib/paper_trail/config.rb +35 -2
- data/lib/paper_trail/frameworks/active_record.rb +4 -5
- data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +7 -0
- data/lib/paper_trail/frameworks/rails.rb +1 -0
- data/lib/paper_trail/frameworks/rails/controller.rb +27 -11
- data/lib/paper_trail/frameworks/rspec.rb +5 -0
- data/lib/paper_trail/frameworks/sinatra.rb +3 -1
- data/lib/paper_trail/has_paper_trail.rb +304 -148
- data/lib/paper_trail/record_history.rb +59 -0
- data/lib/paper_trail/reifier.rb +270 -0
- data/lib/paper_trail/serializers/json.rb +13 -2
- data/lib/paper_trail/serializers/yaml.rb +16 -2
- data/lib/paper_trail/version_association_concern.rb +15 -0
- data/lib/paper_trail/version_concern.rb +160 -122
- data/lib/paper_trail/version_number.rb +3 -3
- data/paper_trail.gemspec +22 -9
- data/spec/generators/install_generator_spec.rb +4 -4
- data/spec/models/animal_spec.rb +36 -0
- data/spec/models/boolit_spec.rb +48 -0
- data/spec/models/callback_modifier_spec.rb +96 -0
- data/spec/models/fluxor_spec.rb +19 -0
- data/spec/models/gadget_spec.rb +14 -12
- data/spec/models/joined_version_spec.rb +9 -9
- data/spec/models/json_version_spec.rb +103 -0
- data/spec/models/kitchen/banana_spec.rb +14 -0
- data/spec/models/not_on_update_spec.rb +19 -0
- data/spec/models/post_with_status_spec.rb +3 -3
- data/spec/models/skipper_spec.rb +46 -0
- data/spec/models/thing_spec.rb +11 -0
- data/spec/models/version_spec.rb +195 -44
- data/spec/models/widget_spec.rb +136 -76
- data/spec/modules/paper_trail_spec.rb +27 -0
- data/spec/modules/version_concern_spec.rb +8 -8
- data/spec/modules/version_number_spec.rb +16 -16
- data/spec/paper_trail/config_spec.rb +52 -0
- data/spec/paper_trail_spec.rb +17 -17
- data/spec/rails_helper.rb +34 -0
- data/spec/requests/articles_spec.rb +10 -14
- data/spec/spec_helper.rb +81 -34
- data/spec/support/alt_db_init.rb +1 -1
- data/test/dummy/app/controllers/application_controller.rb +1 -1
- data/test/dummy/app/controllers/articles_controller.rb +4 -1
- data/test/dummy/app/models/animal.rb +2 -0
- data/test/dummy/app/models/book.rb +4 -0
- data/test/dummy/app/models/boolit.rb +4 -0
- data/test/dummy/app/models/callback_modifier.rb +45 -0
- data/test/dummy/app/models/chapter.rb +9 -0
- data/test/dummy/app/models/citation.rb +5 -0
- data/test/dummy/app/models/customer.rb +4 -0
- data/test/dummy/app/models/editor.rb +4 -0
- data/test/dummy/app/models/editorship.rb +5 -0
- data/test/dummy/app/models/fruit.rb +5 -0
- data/test/dummy/app/models/kitchen/banana.rb +5 -0
- data/test/dummy/app/models/line_item.rb +4 -0
- data/test/dummy/app/models/not_on_update.rb +4 -0
- data/test/dummy/app/models/order.rb +5 -0
- data/test/dummy/app/models/paragraph.rb +5 -0
- data/test/dummy/app/models/person.rb +13 -3
- data/test/dummy/app/models/post.rb +0 -1
- data/test/dummy/app/models/quotation.rb +5 -0
- data/test/dummy/app/models/section.rb +6 -0
- data/test/dummy/app/models/skipper.rb +6 -0
- data/test/dummy/app/models/song.rb +20 -0
- data/test/dummy/app/models/thing.rb +3 -0
- data/test/dummy/app/models/whatchamajigger.rb +4 -0
- data/test/dummy/app/models/widget.rb +5 -0
- data/test/dummy/app/versions/json_version.rb +3 -0
- data/test/dummy/app/versions/kitchen/banana_version.rb +5 -0
- data/test/dummy/config/application.rb +6 -0
- data/test/dummy/config/database.postgres.yml +1 -1
- data/test/dummy/config/environments/test.rb +5 -1
- data/test/dummy/config/initializers/paper_trail.rb +6 -1
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +143 -3
- data/test/dummy/db/schema.rb +169 -25
- data/test/functional/controller_test.rb +4 -2
- data/test/functional/modular_sinatra_test.rb +1 -1
- data/test/functional/sinatra_test.rb +1 -1
- data/test/paper_trail_test.rb +7 -0
- data/test/test_helper.rb +38 -2
- data/test/time_travel_helper.rb +15 -0
- data/test/unit/associations_test.rb +726 -0
- data/test/unit/inheritance_column_test.rb +6 -6
- data/test/unit/model_test.rb +109 -125
- data/test/unit/protected_attrs_test.rb +4 -3
- data/test/unit/serializer_test.rb +6 -6
- data/test/unit/serializers/json_test.rb +17 -4
- data/test/unit/serializers/yaml_test.rb +5 -1
- data/test/unit/version_test.rb +87 -69
- metadata +172 -75
- data/gemfiles/3.0.gemfile +0 -42
- data/test/dummy/public/404.html +0 -26
- data/test/dummy/public/422.html +0 -26
- data/test/dummy/public/500.html +0 -26
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/javascripts/application.js +0 -2
- data/test/dummy/public/javascripts/controls.js +0 -965
- data/test/dummy/public/javascripts/dragdrop.js +0 -974
- data/test/dummy/public/javascripts/effects.js +0 -1123
- data/test/dummy/public/javascripts/prototype.js +0 -6001
- data/test/dummy/public/javascripts/rails.js +0 -175
- data/test/dummy/public/stylesheets/.gitkeep +0 -0
data/paper_trail.gemspec
CHANGED
@@ -19,28 +19,41 @@ Gem::Specification.new do |s|
|
|
19
19
|
|
20
20
|
s.required_rubygems_version = '>= 1.3.6'
|
21
21
|
|
22
|
-
s.add_dependency 'activerecord', ['>= 3.0', '<
|
23
|
-
s.add_dependency 'activesupport', ['>= 3.0', '<
|
22
|
+
s.add_dependency 'activerecord', ['>= 3.0', '< 6.0']
|
23
|
+
s.add_dependency 'activesupport', ['>= 3.0', '< 6.0']
|
24
|
+
s.add_dependency 'request_store', '~> 1.1'
|
24
25
|
|
25
26
|
s.add_development_dependency 'rake', '~> 10.1.1'
|
26
27
|
s.add_development_dependency 'shoulda', '~> 3.5'
|
27
28
|
# s.add_development_dependency 'shoulda-matchers', '~> 1.5' # needed for ActiveRecord < 4
|
28
|
-
s.add_development_dependency 'ffaker',
|
29
|
+
s.add_development_dependency 'ffaker', '<= 1.31.0'
|
29
30
|
s.add_development_dependency 'railties', ['>= 3.0', '< 5.0']
|
30
31
|
s.add_development_dependency 'sinatra', '~> 1.0'
|
31
32
|
s.add_development_dependency 'rack-test', '>= 0.6'
|
32
|
-
s.add_development_dependency 'rspec-rails', '~>
|
33
|
+
s.add_development_dependency 'rspec-rails', '~> 3.1.0'
|
33
34
|
s.add_development_dependency 'generator_spec'
|
34
35
|
s.add_development_dependency 'database_cleaner', '~> 1.2'
|
36
|
+
s.add_development_dependency 'pry-nav'
|
35
37
|
|
36
|
-
#
|
37
|
-
|
38
|
-
s.add_development_dependency '
|
39
|
-
s.add_development_dependency 'mysql2', '~> 0.3'
|
40
|
-
s.add_development_dependency 'pg', '~> 0.17'
|
38
|
+
# Allow time travel in testing. timecop is only supported after 1.9.2 but does a better cleanup at 'return'
|
39
|
+
if RUBY_VERSION < "1.9.2"
|
40
|
+
s.add_development_dependency 'delorean'
|
41
41
|
else
|
42
|
+
s.add_development_dependency 'timecop'
|
43
|
+
end
|
44
|
+
|
45
|
+
if defined?(JRUBY_VERSION)
|
42
46
|
s.add_development_dependency 'activerecord-jdbcsqlite3-adapter', '~> 1.3'
|
43
47
|
s.add_development_dependency 'activerecord-jdbcpostgresql-adapter', '~> 1.3'
|
44
48
|
s.add_development_dependency 'activerecord-jdbcmysql-adapter', '~> 1.3'
|
49
|
+
else
|
50
|
+
s.add_development_dependency 'sqlite3', '~> 1.2'
|
51
|
+
|
52
|
+
# We would prefer to only constrain mysql2 to '~> 0.3',
|
53
|
+
# but a rails bug (https://github.com/rails/rails/issues/21544)
|
54
|
+
# requires us to constrain to '~> 0.3.20' for now.
|
55
|
+
s.add_development_dependency 'mysql2', '~> 0.3.20'
|
56
|
+
|
57
|
+
s.add_development_dependency 'pg', '~> 0.17'
|
45
58
|
end
|
46
59
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'rails_helper'
|
2
2
|
require 'generator_spec/test_case'
|
3
3
|
require File.expand_path('../../../lib/generators/paper_trail/install_generator', __FILE__)
|
4
4
|
|
@@ -15,7 +15,7 @@ describe PaperTrail::InstallGenerator, :type => :generator do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it "generates a migration for creating the 'versions' table" do
|
18
|
-
destination_root.
|
18
|
+
expect(destination_root).to have_structure {
|
19
19
|
directory 'db' do
|
20
20
|
directory 'migrate' do
|
21
21
|
migration 'create_versions' do
|
@@ -36,7 +36,7 @@ describe PaperTrail::InstallGenerator, :type => :generator do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it "generates a migration for creating the 'versions' table" do
|
39
|
-
destination_root.
|
39
|
+
expect(destination_root).to have_structure {
|
40
40
|
directory 'db' do
|
41
41
|
directory 'migrate' do
|
42
42
|
migration 'create_versions' do
|
@@ -50,7 +50,7 @@ describe PaperTrail::InstallGenerator, :type => :generator do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
it "generates a migration for adding the 'object_changes' column to the 'versions' table" do
|
53
|
-
destination_root.
|
53
|
+
expect(destination_root).to have_structure {
|
54
54
|
directory 'db' do
|
55
55
|
directory 'migrate' do
|
56
56
|
migration 'add_object_changes_to_versions' do
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Animal, :type => :model do
|
4
|
+
it { is_expected.to be_versioned }
|
5
|
+
|
6
|
+
describe "STI", :versioning => true do
|
7
|
+
it { expect(Animal.inheritance_column).to eq('species') }
|
8
|
+
|
9
|
+
describe "updates to the `inheritance_column`" do
|
10
|
+
subject { Cat.create!(:name => 'Leo') }
|
11
|
+
|
12
|
+
it "should be allowed" do
|
13
|
+
subject.update_attributes(:name => 'Spike', :species => 'Dog')
|
14
|
+
dog = Animal.find(subject.id)
|
15
|
+
expect(dog).to be_instance_of(Dog)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with callback-methods' do
|
20
|
+
context 'when only has_paper_trail set in super class' do
|
21
|
+
let(:callback_cat) { Cat.create(:name => 'Markus') }
|
22
|
+
|
23
|
+
it 'trails all events' do
|
24
|
+
callback_cat.update_attributes(:name => 'Billie')
|
25
|
+
callback_cat.destroy
|
26
|
+
expect(callback_cat.versions.collect(&:event)).to eq %w(create update destroy)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'does not break reify' do
|
30
|
+
callback_cat.destroy
|
31
|
+
expect { callback_cat.versions.last.reify }.not_to raise_error
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
require Rails.root.join('..', 'custom_json_serializer')
|
3
|
+
|
4
|
+
describe Boolit, :type => :model do
|
5
|
+
it { is_expected.to be_versioned }
|
6
|
+
|
7
|
+
it "has a default scope" do
|
8
|
+
expect(subject.default_scopes).to_not be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "Versioning", :versioning => true do
|
12
|
+
subject { Boolit.create! }
|
13
|
+
before { subject.update_attributes!(:name => Faker::Name.name) }
|
14
|
+
|
15
|
+
it "should have versions" do
|
16
|
+
expect(subject.versions.size).to eq(2)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be able to be reified and persisted" do
|
20
|
+
expect { subject.versions.last.reify.save! }.to_not raise_error
|
21
|
+
end
|
22
|
+
|
23
|
+
context "Instance falls out of default scope" do
|
24
|
+
before { subject.update_attributes!(:scoped => false) }
|
25
|
+
|
26
|
+
it "is NOT scoped" do
|
27
|
+
expect(Boolit.first).to be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should still be able to be reified and persisted" do
|
31
|
+
expect { subject.previous_version.save! }.to_not raise_error
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with `nil` attributes on the live instance" do
|
35
|
+
before do
|
36
|
+
PaperTrail.serializer = CustomJsonSerializer
|
37
|
+
subject.update_attributes!(:name => nil)
|
38
|
+
subject.update_attributes!(:name => Faker::Name.name)
|
39
|
+
end
|
40
|
+
after { PaperTrail.serializer = PaperTrail::Serializers::YAML }
|
41
|
+
|
42
|
+
it "should not overwrite that attribute during the reification process" do
|
43
|
+
expect(subject.previous_version.name).to be_nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe CallbackModifier, :type => :model do
|
4
|
+
with_versioning do
|
5
|
+
describe 'callback-methods', :versioning => true do
|
6
|
+
describe 'paper_trail_on_destroy' do
|
7
|
+
it 'should add :destroy to paper_trail_options[:on]' do
|
8
|
+
modifier = NoArgDestroyModifier.create!(:some_content => Faker::Lorem.sentence)
|
9
|
+
expect(modifier.paper_trail_options[:on]).to eq [:destroy]
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when :before' do
|
13
|
+
it 'should create the version before destroy' do
|
14
|
+
modifier = BeforeDestroyModifier.create!(:some_content => Faker::Lorem.sentence)
|
15
|
+
modifier.test_destroy
|
16
|
+
expect(modifier.versions.last.reify).not_to be_flagged_deleted
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when :after' do
|
21
|
+
it 'should create the version after destroy' do
|
22
|
+
modifier = AfterDestroyModifier.create!(:some_content => Faker::Lorem.sentence)
|
23
|
+
modifier.test_destroy
|
24
|
+
expect(modifier.versions.last.reify).to be_flagged_deleted
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when no argument' do
|
29
|
+
it 'should default to after destroy' do
|
30
|
+
modifier = NoArgDestroyModifier.create!(:some_content => Faker::Lorem.sentence)
|
31
|
+
modifier.test_destroy
|
32
|
+
expect(modifier.versions.last.reify).to be_flagged_deleted
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'paper_trail_on_update' do
|
38
|
+
it 'should add :update to paper_trail_options[:on]' do
|
39
|
+
modifier = UpdateModifier.create!(:some_content => Faker::Lorem.sentence)
|
40
|
+
expect(modifier.paper_trail_options[:on]).to eq [:update]
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should create a version' do
|
44
|
+
modifier = UpdateModifier.create!(:some_content => Faker::Lorem.sentence)
|
45
|
+
modifier.update_attributes! :some_content => 'modified'
|
46
|
+
expect(modifier.versions.last.event).to eq 'update'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'paper_trail_on_create' do
|
51
|
+
it 'should add :create to paper_trail_options[:on]' do
|
52
|
+
modifier = CreateModifier.create!(:some_content => Faker::Lorem.sentence)
|
53
|
+
expect(modifier.paper_trail_options[:on]).to eq [:create]
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should create a version' do
|
57
|
+
modifier = CreateModifier.create!(:some_content => Faker::Lorem.sentence)
|
58
|
+
expect(modifier.versions.last.event).to eq 'create'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when no callback-method used' do
|
63
|
+
it 'should set paper_trail_options[:on] to [:create, :update, :destroy]' do
|
64
|
+
modifier = DefaultModifier.create!(:some_content => Faker::Lorem.sentence)
|
65
|
+
expect(modifier.paper_trail_options[:on]).to eq [:create, :update, :destroy]
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should default to track destroy' do
|
69
|
+
modifier = DefaultModifier.create!(:some_content => Faker::Lorem.sentence)
|
70
|
+
modifier.destroy
|
71
|
+
expect(modifier.versions.last.event).to eq 'destroy'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should default to track update' do
|
75
|
+
modifier = DefaultModifier.create!(:some_content => Faker::Lorem.sentence)
|
76
|
+
modifier.update_attributes! :some_content => 'modified'
|
77
|
+
expect(modifier.versions.last.event).to eq 'update'
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should default to track create' do
|
81
|
+
modifier = DefaultModifier.create!(:some_content => Faker::Lorem.sentence)
|
82
|
+
expect(modifier.versions.last.event).to eq 'create'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when only one callback-method' do
|
87
|
+
it 'does only track the corresponding event' do
|
88
|
+
modifier = CreateModifier.create!(:some_content => Faker::Lorem.sentence)
|
89
|
+
modifier.update_attributes!(:some_content => 'modified')
|
90
|
+
modifier.test_destroy
|
91
|
+
expect(modifier.versions.collect(&:event)).to eq ['create']
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Fluxor, :type => :model do
|
4
|
+
describe '`be_versioned` matcher' do
|
5
|
+
it { is_expected.to_not be_versioned }
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "Methods" do
|
9
|
+
describe "Class" do
|
10
|
+
subject { Fluxor }
|
11
|
+
|
12
|
+
describe "#paper_trail_enabled_for_model?" do
|
13
|
+
it { is_expected.to respond_to(:paper_trail_enabled_for_model?) }
|
14
|
+
|
15
|
+
it { expect(subject.paper_trail_enabled_for_model?).to be false }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/spec/models/gadget_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require '
|
1
|
+
require 'rails_helper'
|
2
2
|
|
3
|
-
describe Gadget do
|
4
|
-
it {
|
3
|
+
describe Gadget, :type => :model do
|
4
|
+
it { is_expected.to be_versioned }
|
5
5
|
|
6
6
|
let(:gadget) { Gadget.create!(:name => 'Wrench', :brand => 'Acme') }
|
7
7
|
|
@@ -22,16 +22,18 @@ describe Gadget do
|
|
22
22
|
describe "Methods" do
|
23
23
|
describe "Instance", :versioning => true do
|
24
24
|
describe "private" do
|
25
|
-
describe
|
25
|
+
describe '#changed_notably?' do
|
26
26
|
subject { Gadget.new(:created_at => Time.now) }
|
27
27
|
|
28
28
|
# apparently the private methods list in Ruby18 is different than in Ruby19+
|
29
|
-
if RUBY_VERSION
|
30
|
-
|
29
|
+
if RUBY_VERSION >= '1.9'
|
30
|
+
it { expect(subject.private_methods).to include(:changed_notably?) }
|
31
|
+
else
|
32
|
+
it { expect(subject.private_methods).to include('changed_notably?') }
|
31
33
|
end
|
32
34
|
|
33
35
|
context "create events" do
|
34
|
-
it { subject.send(:changed_notably?).
|
36
|
+
it { expect(subject.send(:changed_notably?)).to be true }
|
35
37
|
end
|
36
38
|
|
37
39
|
context "update events" do
|
@@ -40,24 +42,24 @@ describe Gadget do
|
|
40
42
|
context "without update timestamps" do
|
41
43
|
it "should only acknowledge non-ignored attrs" do
|
42
44
|
subject.name = 'Wrench'
|
43
|
-
subject.send(:changed_notably?).
|
45
|
+
expect(subject.send(:changed_notably?)).to be true
|
44
46
|
end
|
45
47
|
|
46
|
-
it "should not acknowledge ignored
|
48
|
+
it "should not acknowledge ignored attr (brand)" do
|
47
49
|
subject.brand = 'Acme'
|
48
|
-
subject.send(:changed_notably?).
|
50
|
+
expect(subject.send(:changed_notably?)).to be false
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
52
54
|
context "with update timestamps" do
|
53
55
|
it "should only acknowledge non-ignored attrs" do
|
54
56
|
subject.name, subject.updated_at = 'Wrench', Time.now
|
55
|
-
subject.send(:changed_notably?).
|
57
|
+
expect(subject.send(:changed_notably?)).to be true
|
56
58
|
end
|
57
59
|
|
58
60
|
it "should not acknowledge ignored attrs and timestamps only" do
|
59
61
|
subject.brand, subject.updated_at = 'Acme', Time.now
|
60
|
-
subject.send(:changed_notably?).
|
62
|
+
expect(subject.send(:changed_notably?)).to be false
|
61
63
|
end
|
62
64
|
end
|
63
65
|
end
|
@@ -1,32 +1,32 @@
|
|
1
|
-
require '
|
1
|
+
require 'rails_helper'
|
2
2
|
|
3
|
-
describe JoinedVersion, :versioning => true do
|
4
|
-
it { JoinedVersion.superclass.
|
3
|
+
describe JoinedVersion, :type => :model, :versioning => true do
|
4
|
+
it { expect(JoinedVersion.superclass).to be PaperTrail::Version }
|
5
5
|
|
6
6
|
let(:widget) { Widget.create!(:name => Faker::Name.name) }
|
7
7
|
let(:version) { JoinedVersion.first }
|
8
8
|
|
9
9
|
describe "Scopes" do
|
10
10
|
describe "default_scope" do
|
11
|
-
it { JoinedVersion.default_scopes.
|
11
|
+
it { expect(JoinedVersion.default_scopes).not_to be_empty }
|
12
12
|
end
|
13
13
|
|
14
14
|
describe "VersionConcern::ClassMethods" do
|
15
15
|
before { widget } # persist a widget
|
16
16
|
|
17
|
-
describe
|
17
|
+
describe '#subsequent' do
|
18
18
|
it "shouldn't error out when there is a default_scope that joins" do
|
19
19
|
JoinedVersion.subsequent(version).first
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
describe
|
23
|
+
describe '#preceding' do
|
24
24
|
it "shouldn't error out when there is a default scope that joins" do
|
25
25
|
JoinedVersion.preceding(version).first
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
describe
|
29
|
+
describe '#between' do
|
30
30
|
it "shouldn't error out when there is a default scope that joins" do
|
31
31
|
JoinedVersion.between(Time.now, 1.minute.from_now).first
|
32
32
|
end
|
@@ -35,8 +35,8 @@ describe JoinedVersion, :versioning => true do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
describe "Methods" do
|
38
|
-
describe
|
39
|
-
it {
|
38
|
+
describe '#index' do
|
39
|
+
it { is_expected.to respond_to(:index) }
|
40
40
|
|
41
41
|
it "shouldn't error out when there is a default scope that joins" do
|
42
42
|
widget # persist a widget
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
# The `json_versions` table tests postgres' `json` data type. So, that
|
4
|
+
# table is only created when testing against postgres and ActiveRecord >= 4.
|
5
|
+
if JsonVersion.table_exists?
|
6
|
+
|
7
|
+
describe JsonVersion, :type => :model do
|
8
|
+
it "should include the `VersionConcern` module to get base functionality" do
|
9
|
+
expect(JsonVersion).to include(PaperTrail::VersionConcern)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "Methods" do
|
13
|
+
describe "Class" do
|
14
|
+
|
15
|
+
describe '#where_object' do
|
16
|
+
it { expect(JsonVersion).to respond_to(:where_object) }
|
17
|
+
|
18
|
+
it "escapes values" do
|
19
|
+
f = Fruit.create(:name => 'Bobby')
|
20
|
+
expect(
|
21
|
+
f.
|
22
|
+
versions.
|
23
|
+
where_object(:name => "Robert'; DROP TABLE Students;--").
|
24
|
+
count
|
25
|
+
).to eq(0)
|
26
|
+
end
|
27
|
+
|
28
|
+
context "invalid arguments" do
|
29
|
+
it "should raise an error" do
|
30
|
+
expect { JsonVersion.where_object(:foo) }.to raise_error(ArgumentError)
|
31
|
+
expect { JsonVersion.where_object([]) }.to raise_error(ArgumentError)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "valid arguments", :versioning => true do
|
36
|
+
let(:fruit_names) { %w(apple orange lemon banana lime coconut strawberry blueberry) }
|
37
|
+
let(:fruit) { Fruit.new }
|
38
|
+
let(:name) { 'pomegranate' }
|
39
|
+
let(:color) { Faker::Color.name }
|
40
|
+
|
41
|
+
before do
|
42
|
+
fruit.update_attributes!(:name => name)
|
43
|
+
fruit.update_attributes!(:name => fruit_names.sample, :color => color)
|
44
|
+
fruit.update_attributes!(:name => fruit_names.sample, :color => Faker::Color.name)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be able to locate versions according to their `object` contents" do
|
48
|
+
expect(JsonVersion.where_object(:name => name)).to eq([fruit.versions[1]])
|
49
|
+
expect(JsonVersion.where_object(:color => color)).to eq([fruit.versions[2]])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#where_object_changes' do
|
55
|
+
it { expect(JsonVersion).to respond_to(:where_object_changes) }
|
56
|
+
|
57
|
+
it "escapes values" do
|
58
|
+
f = Fruit.create(:name => 'Bobby')
|
59
|
+
expect(
|
60
|
+
f.
|
61
|
+
versions.
|
62
|
+
where_object_changes(:name => "Robert'; DROP TABLE Students;--").
|
63
|
+
count
|
64
|
+
).to eq(0)
|
65
|
+
end
|
66
|
+
|
67
|
+
context "invalid arguments" do
|
68
|
+
it "should raise an error" do
|
69
|
+
expect { JsonVersion.where_object_changes(:foo) }.to raise_error(ArgumentError)
|
70
|
+
expect { JsonVersion.where_object_changes([]) }.to raise_error(ArgumentError)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "valid arguments", :versioning => true do
|
75
|
+
let(:color) { %w[red green] }
|
76
|
+
let(:fruit) { Fruit.create!(:name => name[0]) }
|
77
|
+
let(:name) { %w[banana kiwi mango] }
|
78
|
+
|
79
|
+
before do
|
80
|
+
fruit.update_attributes!(:name => name[1], :color => color[0])
|
81
|
+
fruit.update_attributes!(:name => name[2], :color => color[1])
|
82
|
+
end
|
83
|
+
|
84
|
+
it "finds versions according to their `object_changes` contents" do
|
85
|
+
expect(
|
86
|
+
fruit.versions.where_object_changes(:name => name[0])
|
87
|
+
).to match_array(fruit.versions[0..1])
|
88
|
+
expect(
|
89
|
+
fruit.versions.where_object_changes(:color => color[0])
|
90
|
+
).to match_array(fruit.versions[1..2])
|
91
|
+
end
|
92
|
+
|
93
|
+
it "finds versions with multiple attributes changed" do
|
94
|
+
expect(
|
95
|
+
fruit.versions.where_object_changes(:color => color[0], :name => name[0])
|
96
|
+
).to match_array([fruit.versions[1]])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|