paper_trail 4.0.0 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CONTRIBUTING.md +105 -0
- data/.github/ISSUE_TEMPLATE.md +13 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +100 -0
- data/.rubocop_todo.yml +14 -0
- data/.travis.yml +11 -10
- data/Appraisals +37 -0
- data/CHANGELOG.md +173 -8
- data/Gemfile +1 -1
- data/README.md +641 -470
- data/Rakefile +19 -19
- data/doc/bug_report_template.rb +71 -0
- data/doc/warning_about_not_setting_whodunnit.md +32 -0
- data/gemfiles/ar3.gemfile +18 -0
- data/gemfiles/ar4.gemfile +7 -0
- data/gemfiles/ar5.gemfile +13 -0
- data/lib/generators/paper_trail/install_generator.rb +26 -18
- data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb +3 -1
- data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb +2 -0
- data/lib/generators/paper_trail/templates/create_version_associations.rb +9 -4
- data/lib/generators/paper_trail/templates/create_versions.rb +53 -5
- data/lib/paper_trail/attribute_serializers/README.md +10 -0
- data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +58 -0
- data/lib/paper_trail/attribute_serializers/legacy_active_record_shim.rb +48 -0
- data/lib/paper_trail/attribute_serializers/object_attribute.rb +39 -0
- data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +42 -0
- data/lib/paper_trail/cleaner.rb +41 -18
- data/lib/paper_trail/config.rb +42 -26
- data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +5 -1
- data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +6 -2
- data/lib/paper_trail/frameworks/active_record.rb +2 -2
- data/lib/paper_trail/frameworks/cucumber.rb +1 -0
- data/lib/paper_trail/frameworks/rails/controller.rb +50 -14
- data/lib/paper_trail/frameworks/rails/engine.rb +6 -1
- data/lib/paper_trail/frameworks/rails.rb +2 -7
- data/lib/paper_trail/frameworks/rspec/helpers.rb +3 -1
- data/lib/paper_trail/frameworks/rspec.rb +5 -5
- data/lib/paper_trail/frameworks/sinatra.rb +8 -5
- data/lib/paper_trail/has_paper_trail.rb +381 -221
- data/lib/paper_trail/record_history.rb +57 -0
- data/lib/paper_trail/reifier.rb +450 -0
- data/lib/paper_trail/serializers/json.rb +7 -7
- data/lib/paper_trail/serializers/yaml.rb +31 -12
- data/lib/paper_trail/version_association_concern.rb +6 -2
- data/lib/paper_trail/version_concern.rb +200 -287
- data/lib/paper_trail/version_number.rb +6 -9
- data/lib/paper_trail.rb +169 -137
- data/paper_trail.gemspec +41 -43
- data/spec/generators/install_generator_spec.rb +24 -25
- data/spec/generators/paper_trail/templates/create_versions_spec.rb +51 -0
- data/spec/models/animal_spec.rb +23 -6
- data/spec/models/boolit_spec.rb +8 -8
- data/spec/models/callback_modifier_spec.rb +96 -0
- data/spec/models/car_spec.rb +13 -0
- data/spec/models/fluxor_spec.rb +3 -3
- data/spec/models/gadget_spec.rb +19 -19
- data/spec/models/joined_version_spec.rb +3 -3
- data/spec/models/json_version_spec.rb +50 -28
- data/spec/models/kitchen/banana_spec.rb +3 -3
- data/spec/models/not_on_update_spec.rb +7 -4
- data/spec/models/post_with_status_spec.rb +13 -3
- data/spec/models/skipper_spec.rb +40 -11
- data/spec/models/thing_spec.rb +4 -4
- data/spec/models/truck_spec.rb +5 -0
- data/spec/models/vehicle_spec.rb +5 -0
- data/spec/models/version_spec.rb +103 -59
- data/spec/models/widget_spec.rb +86 -55
- data/spec/modules/paper_trail_spec.rb +2 -2
- data/spec/modules/version_concern_spec.rb +11 -12
- data/spec/modules/version_number_spec.rb +3 -4
- data/spec/paper_trail/config_spec.rb +33 -0
- data/spec/paper_trail_spec.rb +16 -14
- data/spec/rails_helper.rb +10 -9
- data/spec/requests/articles_spec.rb +11 -7
- data/spec/spec_helper.rb +42 -17
- data/spec/support/alt_db_init.rb +8 -13
- data/test/custom_json_serializer.rb +3 -3
- data/test/dummy/Rakefile +2 -2
- data/test/dummy/app/controllers/application_controller.rb +21 -8
- data/test/dummy/app/controllers/articles_controller.rb +11 -8
- data/test/dummy/app/controllers/widgets_controller.rb +13 -12
- data/test/dummy/app/models/animal.rb +1 -1
- data/test/dummy/app/models/article.rb +19 -11
- data/test/dummy/app/models/authorship.rb +1 -1
- data/test/dummy/app/models/bar_habtm.rb +4 -0
- data/test/dummy/app/models/book.rb +4 -4
- data/test/dummy/app/models/boolit.rb +1 -1
- data/test/dummy/app/models/callback_modifier.rb +45 -0
- data/test/dummy/app/models/car.rb +3 -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 +1 -1
- data/test/dummy/app/models/document.rb +2 -2
- data/test/dummy/app/models/editor.rb +1 -1
- data/test/dummy/app/models/foo_habtm.rb +5 -0
- data/test/dummy/app/models/fruit.rb +2 -2
- data/test/dummy/app/models/gadget.rb +1 -1
- data/test/dummy/app/models/kitchen/banana.rb +1 -1
- data/test/dummy/app/models/legacy_widget.rb +2 -2
- data/test/dummy/app/models/line_item.rb +1 -1
- data/test/dummy/app/models/not_on_update.rb +1 -1
- data/test/dummy/app/models/paragraph.rb +5 -0
- data/test/dummy/app/models/person.rb +6 -6
- data/test/dummy/app/models/post.rb +1 -1
- data/test/dummy/app/models/post_with_status.rb +1 -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 +2 -2
- data/test/dummy/app/models/song.rb +13 -4
- data/test/dummy/app/models/thing.rb +2 -2
- data/test/dummy/app/models/translation.rb +2 -2
- data/test/dummy/app/models/truck.rb +4 -0
- data/test/dummy/app/models/vehicle.rb +4 -0
- data/test/dummy/app/models/whatchamajigger.rb +1 -1
- data/test/dummy/app/models/widget.rb +7 -6
- data/test/dummy/app/versions/joined_version.rb +4 -3
- data/test/dummy/app/versions/json_version.rb +1 -1
- data/test/dummy/app/versions/kitchen/banana_version.rb +1 -1
- data/test/dummy/app/versions/post_version.rb +2 -2
- data/test/dummy/config/application.rb +20 -9
- data/test/dummy/config/boot.rb +5 -5
- data/test/dummy/config/database.postgres.yml +1 -1
- data/test/dummy/config/environment.rb +1 -1
- data/test/dummy/config/environments/development.rb +4 -3
- data/test/dummy/config/environments/production.rb +3 -2
- data/test/dummy/config/environments/test.rb +15 -5
- data/test/dummy/config/initializers/backtrace_silencers.rb +4 -2
- data/test/dummy/config/initializers/paper_trail.rb +4 -3
- data/test/dummy/config/initializers/secret_token.rb +3 -1
- data/test/dummy/config/initializers/session_store.rb +1 -1
- data/test/dummy/config/routes.rb +2 -2
- data/test/dummy/config.ru +1 -1
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +148 -68
- data/test/dummy/db/schema.rb +119 -31
- data/test/dummy/script/rails +6 -4
- data/test/functional/controller_test.rb +34 -35
- data/test/functional/enabled_for_controller_test.rb +6 -7
- data/test/functional/modular_sinatra_test.rb +43 -38
- data/test/functional/sinatra_test.rb +49 -40
- data/test/functional/thread_safety_test.rb +4 -6
- data/test/paper_trail_test.rb +15 -14
- data/test/test_helper.rb +78 -18
- data/test/time_travel_helper.rb +1 -15
- data/test/unit/associations_test.rb +1016 -0
- data/test/unit/cleaner_test.rb +66 -60
- data/test/unit/inheritance_column_test.rb +19 -19
- data/test/unit/model_test.rb +646 -1071
- data/test/unit/protected_attrs_test.rb +19 -14
- data/test/unit/serializer_test.rb +44 -43
- data/test/unit/serializers/json_test.rb +28 -21
- data/test/unit/serializers/mixin_json_test.rb +15 -14
- data/test/unit/serializers/mixin_yaml_test.rb +20 -16
- data/test/unit/serializers/yaml_test.rb +16 -14
- data/test/unit/timestamp_test.rb +10 -12
- data/test/unit/version_test.rb +88 -70
- metadata +166 -72
- data/gemfiles/3.0.gemfile +0 -52
@@ -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: FFaker::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: FFaker::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: FFaker::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 before destroy" do
|
30
|
+
modifier = NoArgDestroyModifier.create!(some_content: FFaker::Lorem.sentence)
|
31
|
+
modifier.test_destroy
|
32
|
+
expect(modifier.versions.last.reify).not_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: FFaker::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: FFaker::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: FFaker::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: FFaker::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: FFaker::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: FFaker::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: FFaker::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: FFaker::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: FFaker::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,13 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
describe Car, type: :model do
|
4
|
+
it { is_expected.to be_versioned }
|
5
|
+
|
6
|
+
describe "changeset", versioning: true do
|
7
|
+
it "has the expected keys (see issue 738)" do
|
8
|
+
car = Car.create!(name: "Alice")
|
9
|
+
car.update_attributes(name: "Bob")
|
10
|
+
assert_includes car.versions.last.changeset.keys, "name"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/spec/models/fluxor_spec.rb
CHANGED
data/spec/models/gadget_spec.rb
CHANGED
@@ -1,36 +1,34 @@
|
|
1
|
-
require
|
1
|
+
require "rails_helper"
|
2
2
|
|
3
|
-
describe Gadget, :
|
3
|
+
describe Gadget, type: :model do
|
4
4
|
it { is_expected.to be_versioned }
|
5
5
|
|
6
|
-
let(:gadget) { Gadget.create!(:
|
6
|
+
let(:gadget) { Gadget.create!(name: "Wrench", brand: "Acme") }
|
7
7
|
|
8
|
-
describe "updates", :
|
8
|
+
describe "updates", versioning: true do
|
9
9
|
it "should generate a version for updates to `name` attribute" do
|
10
|
-
expect { gadget.update_attribute(:name,
|
10
|
+
expect { gadget.update_attribute(:name, "Hammer").to change { gadget.versions.size }.by(1) }
|
11
11
|
end
|
12
12
|
|
13
13
|
it "should ignore for updates to `brand` attribute" do
|
14
|
-
expect { gadget.update_attribute(:brand,
|
14
|
+
expect { gadget.update_attribute(:brand, "Stanley") }.to_not change { gadget.versions.size }
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should still generate a version when only the `updated_at` attribute is updated" do
|
18
|
-
|
18
|
+
# Plus 1 second because MySQL lacks sub-second resolution
|
19
|
+
expect {
|
20
|
+
gadget.update_attribute(:updated_at, Time.now + 1)
|
21
|
+
}.to change { gadget.versions.size }.by(1)
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
25
|
describe "Methods" do
|
23
|
-
describe "Instance", :
|
26
|
+
describe "Instance", versioning: true do
|
24
27
|
describe "private" do
|
25
28
|
describe '#changed_notably?' do
|
26
|
-
subject { Gadget.new(:
|
29
|
+
subject { Gadget.new(created_at: Time.now) }
|
27
30
|
|
28
|
-
|
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?') }
|
33
|
-
end
|
31
|
+
it { expect(subject.private_methods).to include(:changed_notably?) }
|
34
32
|
|
35
33
|
context "create events" do
|
36
34
|
it { expect(subject.send(:changed_notably?)).to be true }
|
@@ -41,24 +39,26 @@ describe Gadget, :type => :model do
|
|
41
39
|
|
42
40
|
context "without update timestamps" do
|
43
41
|
it "should only acknowledge non-ignored attrs" do
|
44
|
-
subject.name =
|
42
|
+
subject.name = "Wrench"
|
45
43
|
expect(subject.send(:changed_notably?)).to be true
|
46
44
|
end
|
47
45
|
|
48
46
|
it "should not acknowledge ignored attr (brand)" do
|
49
|
-
subject.brand =
|
47
|
+
subject.brand = "Acme"
|
50
48
|
expect(subject.send(:changed_notably?)).to be false
|
51
49
|
end
|
52
50
|
end
|
53
51
|
|
54
52
|
context "with update timestamps" do
|
55
53
|
it "should only acknowledge non-ignored attrs" do
|
56
|
-
subject.name
|
54
|
+
subject.name = "Wrench"
|
55
|
+
subject.updated_at = Time.now
|
57
56
|
expect(subject.send(:changed_notably?)).to be true
|
58
57
|
end
|
59
58
|
|
60
59
|
it "should not acknowledge ignored attrs and timestamps only" do
|
61
|
-
subject.brand
|
60
|
+
subject.brand = "Acme"
|
61
|
+
subject.updated_at = Time.now
|
62
62
|
expect(subject.send(:changed_notably?)).to be false
|
63
63
|
end
|
64
64
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require "rails_helper"
|
2
2
|
|
3
|
-
describe JoinedVersion, :
|
3
|
+
describe JoinedVersion, type: :model, versioning: true do
|
4
4
|
it { expect(JoinedVersion.superclass).to be PaperTrail::Version }
|
5
5
|
|
6
|
-
let(:widget) { Widget.create!(:
|
6
|
+
let(:widget) { Widget.create!(name: FFaker::Name.name) }
|
7
7
|
let(:version) { JoinedVersion.first }
|
8
8
|
|
9
9
|
describe "Scopes" do
|
@@ -1,18 +1,29 @@
|
|
1
|
-
|
1
|
+
require "rails_helper"
|
2
2
|
|
3
|
-
|
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?
|
4
6
|
|
5
|
-
describe JsonVersion, :
|
7
|
+
describe JsonVersion, type: :model do
|
6
8
|
it "should include the `VersionConcern` module to get base functionality" do
|
7
9
|
expect(JsonVersion).to include(PaperTrail::VersionConcern)
|
8
10
|
end
|
9
11
|
|
10
12
|
describe "Methods" do
|
11
13
|
describe "Class" do
|
12
|
-
|
13
14
|
describe '#where_object' do
|
14
15
|
it { expect(JsonVersion).to respond_to(:where_object) }
|
15
16
|
|
17
|
+
it "escapes values" do
|
18
|
+
f = Fruit.create(name: "Bobby")
|
19
|
+
expect(
|
20
|
+
f.
|
21
|
+
versions.
|
22
|
+
where_object(name: "Robert'; DROP TABLE Students;--").
|
23
|
+
count
|
24
|
+
).to eq(0)
|
25
|
+
end
|
26
|
+
|
16
27
|
context "invalid arguments" do
|
17
28
|
it "should raise an error" do
|
18
29
|
expect { JsonVersion.where_object(:foo) }.to raise_error(ArgumentError)
|
@@ -20,21 +31,21 @@ if JsonVersion.table_exists?
|
|
20
31
|
end
|
21
32
|
end
|
22
33
|
|
23
|
-
context "valid arguments", :
|
34
|
+
context "valid arguments", versioning: true do
|
24
35
|
let(:fruit_names) { %w(apple orange lemon banana lime coconut strawberry blueberry) }
|
25
36
|
let(:fruit) { Fruit.new }
|
26
|
-
let(:name) {
|
27
|
-
let(:color) {
|
37
|
+
let(:name) { "pomegranate" }
|
38
|
+
let(:color) { FFaker::Color.name }
|
28
39
|
|
29
40
|
before do
|
30
|
-
fruit.update_attributes!(:
|
31
|
-
fruit.update_attributes!(:
|
32
|
-
fruit.update_attributes!(:
|
41
|
+
fruit.update_attributes!(name: name)
|
42
|
+
fruit.update_attributes!(name: fruit_names.sample, color: color)
|
43
|
+
fruit.update_attributes!(name: fruit_names.sample, color: FFaker::Color.name)
|
33
44
|
end
|
34
45
|
|
35
46
|
it "should be able to locate versions according to their `object` contents" do
|
36
|
-
expect(JsonVersion.where_object(:
|
37
|
-
expect(JsonVersion.where_object(:
|
47
|
+
expect(JsonVersion.where_object(name: name)).to eq([fruit.versions[1]])
|
48
|
+
expect(JsonVersion.where_object(color: color)).to eq([fruit.versions[2]])
|
38
49
|
end
|
39
50
|
end
|
40
51
|
end
|
@@ -42,6 +53,16 @@ if JsonVersion.table_exists?
|
|
42
53
|
describe '#where_object_changes' do
|
43
54
|
it { expect(JsonVersion).to respond_to(:where_object_changes) }
|
44
55
|
|
56
|
+
it "escapes values" do
|
57
|
+
f = Fruit.create(name: "Bobby")
|
58
|
+
expect(
|
59
|
+
f.
|
60
|
+
versions.
|
61
|
+
where_object_changes(name: "Robert'; DROP TABLE Students;--").
|
62
|
+
count
|
63
|
+
).to eq(0)
|
64
|
+
end
|
65
|
+
|
45
66
|
context "invalid arguments" do
|
46
67
|
it "should raise an error" do
|
47
68
|
expect { JsonVersion.where_object_changes(:foo) }.to raise_error(ArgumentError)
|
@@ -49,32 +70,33 @@ if JsonVersion.table_exists?
|
|
49
70
|
end
|
50
71
|
end
|
51
72
|
|
52
|
-
context "valid arguments", :
|
53
|
-
let(:
|
54
|
-
let(:
|
55
|
-
let(:
|
56
|
-
let(:name) { 'pomegranate' }
|
57
|
-
let(:color) { Faker::Color.name }
|
73
|
+
context "valid arguments", versioning: true do
|
74
|
+
let(:color) { %w(red green) }
|
75
|
+
let(:fruit) { Fruit.create!(name: name[0]) }
|
76
|
+
let(:name) { %w(banana kiwi mango) }
|
58
77
|
|
59
78
|
before do
|
60
|
-
fruit.update_attributes!(:name
|
61
|
-
fruit.update_attributes!(:name
|
62
|
-
fruit.update_attributes!(:name => fruit_names.sample, :color => Faker::Color.name)
|
79
|
+
fruit.update_attributes!(name: name[1], color: color[0])
|
80
|
+
fruit.update_attributes!(name: name[2], color: color[1])
|
63
81
|
end
|
64
82
|
|
65
|
-
it "
|
66
|
-
expect(
|
67
|
-
|
83
|
+
it "finds versions according to their `object_changes` contents" do
|
84
|
+
expect(
|
85
|
+
fruit.versions.where_object_changes(name: name[0])
|
86
|
+
).to match_array(fruit.versions[0..1])
|
87
|
+
expect(
|
88
|
+
fruit.versions.where_object_changes(color: color[0])
|
89
|
+
).to match_array(fruit.versions[1..2])
|
68
90
|
end
|
69
91
|
|
70
|
-
it "
|
71
|
-
expect(
|
92
|
+
it "finds versions with multiple attributes changed" do
|
93
|
+
expect(
|
94
|
+
fruit.versions.where_object_changes(color: color[0], name: name[0])
|
95
|
+
).to match_array([fruit.versions[1]])
|
72
96
|
end
|
73
97
|
end
|
74
98
|
end
|
75
99
|
end
|
76
|
-
|
77
100
|
end
|
78
101
|
end
|
79
|
-
|
80
102
|
end
|
@@ -1,11 +1,11 @@
|
|
1
|
-
require
|
1
|
+
require "rails_helper"
|
2
2
|
|
3
3
|
module Kitchen
|
4
|
-
describe Banana, :
|
4
|
+
describe Banana, type: :model do
|
5
5
|
it { is_expected.to be_versioned }
|
6
6
|
|
7
7
|
describe '#versions' do
|
8
|
-
it "returns instances of Kitchen::BananaVersion", :
|
8
|
+
it "returns instances of Kitchen::BananaVersion", versioning: true do
|
9
9
|
banana = described_class.create!
|
10
10
|
expect(banana.versions.first).to be_a(Kitchen::BananaVersion)
|
11
11
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require "rails_helper"
|
2
2
|
|
3
|
-
describe NotOnUpdate, :
|
4
|
-
describe "#touch_with_version", :
|
3
|
+
describe NotOnUpdate, type: :model do
|
4
|
+
describe "#touch_with_version", versioning: true do
|
5
5
|
let!(:record) { described_class.create! }
|
6
6
|
|
7
7
|
it "should create a version, regardless" do
|
@@ -12,7 +12,10 @@ describe NotOnUpdate, :type => :model do
|
|
12
12
|
|
13
13
|
it "increments the `:updated_at` timestamp" do
|
14
14
|
before = record.updated_at
|
15
|
-
|
15
|
+
# Travel 1 second because MySQL lacks sub-second resolution
|
16
|
+
Timecop.travel(1) do
|
17
|
+
record.touch_with_version
|
18
|
+
end
|
16
19
|
expect(record.updated_at).to be > before
|
17
20
|
end
|
18
21
|
end
|
@@ -1,17 +1,27 @@
|
|
1
|
-
require
|
1
|
+
require "rails_helper"
|
2
2
|
|
3
3
|
# This model is in the test suite soley for the purpose of testing ActiveRecord::Enum,
|
4
4
|
# which is available in ActiveRecord4+ only
|
5
|
-
describe PostWithStatus, :
|
5
|
+
describe PostWithStatus, type: :model do
|
6
6
|
if defined?(ActiveRecord::Enum)
|
7
7
|
with_versioning do
|
8
|
-
let(:post) { PostWithStatus.create!(:
|
8
|
+
let(:post) { PostWithStatus.create!(status: "draft") }
|
9
9
|
|
10
10
|
it "should stash the enum value properly in versions" do
|
11
11
|
post.published!
|
12
12
|
post.archived!
|
13
13
|
expect(post.previous_version.published?).to be true
|
14
14
|
end
|
15
|
+
|
16
|
+
context "storing enum object_changes" do
|
17
|
+
subject { post.versions.last }
|
18
|
+
|
19
|
+
it "should stash the enum value properly in versions object_changes" do
|
20
|
+
post.published!
|
21
|
+
post.archived!
|
22
|
+
expect(subject.changeset["status"]).to eql %w(published archived)
|
23
|
+
end
|
24
|
+
end
|
15
25
|
end
|
16
26
|
end
|
17
27
|
end
|
data/spec/models/skipper_spec.rb
CHANGED
@@ -1,16 +1,45 @@
|
|
1
|
-
require
|
1
|
+
require "rails_helper"
|
2
2
|
|
3
|
-
describe Skipper, :
|
4
|
-
|
5
|
-
|
6
|
-
let(:t1) { Time.zone.local(2015, 7, 15, 20, 34, 0) }
|
7
|
-
let(:t2) { Time.zone.local(2015, 7, 15, 20, 34, 30) }
|
3
|
+
describe Skipper, type: :model do
|
4
|
+
with_versioning do
|
5
|
+
it { is_expected.to be_versioned }
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
describe "#update_attributes!", versioning: true do
|
8
|
+
context "updating a skipped attribute" do
|
9
|
+
let(:t1) { Time.zone.local(2015, 7, 15, 20, 34, 0) }
|
10
|
+
let(:t2) { Time.zone.local(2015, 7, 15, 20, 34, 30) }
|
11
|
+
|
12
|
+
it "should not create a version" do
|
13
|
+
skipper = Skipper.create!(another_timestamp: t1)
|
14
|
+
expect {
|
15
|
+
skipper.update_attributes!(another_timestamp: t2)
|
16
|
+
}.to_not change { skipper.versions.length }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "reify" do
|
22
|
+
context "reifying a with a skipped attribute" do
|
23
|
+
let(:t1) { Time.zone.local(2015, 7, 15, 20, 34, 0) }
|
24
|
+
let(:t2) { Time.zone.local(2015, 7, 15, 20, 34, 30) }
|
25
|
+
|
26
|
+
context "without preserve (default)" do
|
27
|
+
it "should have no timestamp" do
|
28
|
+
skipper = Skipper.create!(another_timestamp: t1)
|
29
|
+
skipper.update_attributes!(another_timestamp: t2, name: "Foobar")
|
30
|
+
skipper = skipper.versions.last.reify
|
31
|
+
expect(skipper.another_timestamp).to be(nil)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "with preserve" do
|
36
|
+
it "should preserve its timestamp" do
|
37
|
+
skipper = Skipper.create!(another_timestamp: t1)
|
38
|
+
skipper.update_attributes!(another_timestamp: t2, name: "Foobar")
|
39
|
+
skipper = skipper.versions.last.reify(unversioned_attributes: :preserve)
|
40
|
+
expect(skipper.another_timestamp).to eq(t2)
|
41
|
+
end
|
42
|
+
end
|
14
43
|
end
|
15
44
|
end
|
16
45
|
end
|
data/spec/models/thing_spec.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
1
|
+
require "rails_helper"
|
2
2
|
|
3
|
-
describe Thing, :
|
3
|
+
describe Thing, type: :model do
|
4
4
|
it { is_expected.to be_versioned }
|
5
5
|
|
6
|
-
describe "should not store object_changes", :
|
7
|
-
let(:thing) { Thing.create(:
|
6
|
+
describe "should not store object_changes", versioning: true do
|
7
|
+
let(:thing) { Thing.create(name: "pencil") }
|
8
8
|
|
9
9
|
it { expect(thing.versions.last.object_changes).to be_nil }
|
10
10
|
end
|