paper_trail 7.1.0 → 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/paper_trail/record_trail.rb +1 -1
- data/lib/paper_trail/version_number.rb +1 -1
- metadata +3 -274
- data/.github/CONTRIBUTING.md +0 -151
- data/.github/ISSUE_TEMPLATE.md +0 -13
- data/.gitignore +0 -23
- data/.rspec +0 -2
- data/.rubocop.yml +0 -135
- data/.rubocop_todo.yml +0 -41
- data/.travis.yml +0 -41
- data/Appraisals +0 -26
- data/CHANGELOG.md +0 -739
- data/Gemfile +0 -2
- data/MIT-LICENSE +0 -20
- data/README.md +0 -1613
- data/Rakefile +0 -38
- data/doc/bug_report_template.rb +0 -73
- data/doc/triage.md +0 -27
- data/doc/warning_about_not_setting_whodunnit.md +0 -33
- data/gemfiles/ar_4.0.gemfile +0 -7
- data/gemfiles/ar_4.2.gemfile +0 -7
- data/gemfiles/ar_5.0.gemfile +0 -8
- data/gemfiles/ar_5.1.gemfile +0 -8
- data/gemfiles/ar_master.gemfile +0 -9
- data/lib/generators/paper_trail/default_initializer.rb +0 -0
- data/paper_trail.gemspec +0 -49
- data/spec/controllers/articles_controller_spec.rb +0 -28
- data/spec/controllers/widgets_controller_spec.rb +0 -85
- data/spec/dummy_app/Rakefile +0 -7
- data/spec/dummy_app/app/controllers/application_controller.rb +0 -30
- data/spec/dummy_app/app/controllers/articles_controller.rb +0 -16
- data/spec/dummy_app/app/controllers/test_controller.rb +0 -5
- data/spec/dummy_app/app/controllers/widgets_controller.rb +0 -28
- data/spec/dummy_app/app/models/animal.rb +0 -4
- data/spec/dummy_app/app/models/article.rb +0 -25
- data/spec/dummy_app/app/models/authorship.rb +0 -5
- data/spec/dummy_app/app/models/bar_habtm.rb +0 -4
- data/spec/dummy_app/app/models/book.rb +0 -9
- data/spec/dummy_app/app/models/boolit.rb +0 -4
- data/spec/dummy_app/app/models/callback_modifier.rb +0 -45
- data/spec/dummy_app/app/models/car.rb +0 -3
- data/spec/dummy_app/app/models/cat.rb +0 -2
- data/spec/dummy_app/app/models/chapter.rb +0 -9
- data/spec/dummy_app/app/models/citation.rb +0 -5
- data/spec/dummy_app/app/models/custom_primary_key_record.rb +0 -15
- data/spec/dummy_app/app/models/customer.rb +0 -4
- data/spec/dummy_app/app/models/document.rb +0 -8
- data/spec/dummy_app/app/models/dog.rb +0 -2
- data/spec/dummy_app/app/models/editor.rb +0 -4
- data/spec/dummy_app/app/models/editorship.rb +0 -5
- data/spec/dummy_app/app/models/elephant.rb +0 -3
- data/spec/dummy_app/app/models/fluxor.rb +0 -3
- data/spec/dummy_app/app/models/foo_habtm.rb +0 -5
- data/spec/dummy_app/app/models/foo_widget.rb +0 -2
- data/spec/dummy_app/app/models/fruit.rb +0 -5
- data/spec/dummy_app/app/models/gadget.rb +0 -3
- data/spec/dummy_app/app/models/kitchen/banana.rb +0 -5
- data/spec/dummy_app/app/models/legacy_widget.rb +0 -6
- data/spec/dummy_app/app/models/line_item.rb +0 -4
- data/spec/dummy_app/app/models/not_on_update.rb +0 -4
- data/spec/dummy_app/app/models/on/create.rb +0 -6
- data/spec/dummy_app/app/models/on/destroy.rb +0 -6
- data/spec/dummy_app/app/models/on/empty_array.rb +0 -6
- data/spec/dummy_app/app/models/on/update.rb +0 -6
- data/spec/dummy_app/app/models/order.rb +0 -5
- data/spec/dummy_app/app/models/paragraph.rb +0 -5
- data/spec/dummy_app/app/models/person.rb +0 -39
- data/spec/dummy_app/app/models/post.rb +0 -3
- data/spec/dummy_app/app/models/post_with_status.rb +0 -7
- data/spec/dummy_app/app/models/quotation.rb +0 -5
- data/spec/dummy_app/app/models/section.rb +0 -6
- data/spec/dummy_app/app/models/skipper.rb +0 -3
- data/spec/dummy_app/app/models/song.rb +0 -37
- data/spec/dummy_app/app/models/thing.rb +0 -3
- data/spec/dummy_app/app/models/translation.rb +0 -11
- data/spec/dummy_app/app/models/truck.rb +0 -4
- data/spec/dummy_app/app/models/vehicle.rb +0 -4
- data/spec/dummy_app/app/models/whatchamajigger.rb +0 -4
- data/spec/dummy_app/app/models/widget.rb +0 -8
- data/spec/dummy_app/app/models/wotsit.rb +0 -8
- data/spec/dummy_app/app/versions/custom_primary_key_record_version.rb +0 -3
- data/spec/dummy_app/app/versions/joined_version.rb +0 -6
- data/spec/dummy_app/app/versions/json_version.rb +0 -3
- data/spec/dummy_app/app/versions/kitchen/banana_version.rb +0 -5
- data/spec/dummy_app/app/versions/post_version.rb +0 -3
- data/spec/dummy_app/config.ru +0 -4
- data/spec/dummy_app/config/application.rb +0 -39
- data/spec/dummy_app/config/boot.rb +0 -24
- data/spec/dummy_app/config/database.mysql.yml +0 -19
- data/spec/dummy_app/config/database.postgres.yml +0 -15
- data/spec/dummy_app/config/database.sqlite.yml +0 -15
- data/spec/dummy_app/config/environment.rb +0 -5
- data/spec/dummy_app/config/environments/development.rb +0 -36
- data/spec/dummy_app/config/environments/production.rb +0 -74
- data/spec/dummy_app/config/environments/test.rb +0 -46
- data/spec/dummy_app/config/initializers/backtrace_silencers.rb +0 -9
- data/spec/dummy_app/config/initializers/inflections.rb +0 -10
- data/spec/dummy_app/config/initializers/mime_types.rb +0 -5
- data/spec/dummy_app/config/initializers/paper_trail.rb +0 -1
- data/spec/dummy_app/config/initializers/secret_token.rb +0 -9
- data/spec/dummy_app/config/initializers/session_store.rb +0 -8
- data/spec/dummy_app/config/locales/en.yml +0 -5
- data/spec/dummy_app/config/routes.rb +0 -4
- data/spec/dummy_app/db/migrate/20110208155312_set_up_test_tables.rb +0 -344
- data/spec/dummy_app/db/schema.rb +0 -298
- data/spec/generators/install_generator_spec.rb +0 -88
- data/spec/models/animal_spec.rb +0 -61
- data/spec/models/article_spec.rb +0 -186
- data/spec/models/boolit_spec.rb +0 -41
- data/spec/models/callback_modifier_spec.rb +0 -92
- data/spec/models/car_spec.rb +0 -13
- data/spec/models/custom_primary_key_record_spec.rb +0 -18
- data/spec/models/document_spec.rb +0 -57
- data/spec/models/gadget_spec.rb +0 -63
- data/spec/models/joined_version_spec.rb +0 -41
- data/spec/models/json_version_spec.rb +0 -101
- data/spec/models/kitchen/banana_spec.rb +0 -14
- data/spec/models/legacy_widget_spec.rb +0 -40
- data/spec/models/not_on_update_spec.rb +0 -22
- data/spec/models/on/create_spec.rb +0 -27
- data/spec/models/on/destroy_spec.rb +0 -27
- data/spec/models/on/empty_array_spec.rb +0 -30
- data/spec/models/on/update_spec.rb +0 -27
- data/spec/models/post_with_status_spec.rb +0 -46
- data/spec/models/skipper_spec.rb +0 -42
- data/spec/models/thing_spec.rb +0 -11
- data/spec/models/translation_spec.rb +0 -70
- data/spec/models/vehicle_spec.rb +0 -5
- data/spec/models/version_spec.rb +0 -282
- data/spec/models/widget_spec.rb +0 -338
- data/spec/modules/paper_trail_spec.rb +0 -27
- data/spec/modules/version_concern_spec.rb +0 -28
- data/spec/modules/version_number_spec.rb +0 -18
- data/spec/paper_trail/associations_spec.rb +0 -965
- data/spec/paper_trail/cleaner_spec.rb +0 -152
- data/spec/paper_trail/config_spec.rb +0 -45
- data/spec/paper_trail/model_spec.rb +0 -992
- data/spec/paper_trail/serializer_spec.rb +0 -85
- data/spec/paper_trail/serializers/custom_json_serializer_spec.rb +0 -18
- data/spec/paper_trail/serializers/custom_yaml_serializer_spec.rb +0 -45
- data/spec/paper_trail/serializers/json_spec.rb +0 -57
- data/spec/paper_trail/serializers/yaml_spec.rb +0 -42
- data/spec/paper_trail/thread_safety_spec.rb +0 -44
- data/spec/paper_trail/version_limit_spec.rb +0 -55
- data/spec/paper_trail/version_spec.rb +0 -96
- data/spec/paper_trail_spec.rb +0 -122
- data/spec/requests/articles_spec.rb +0 -34
- data/spec/spec_helper.rb +0 -78
- data/spec/support/alt_db_init.rb +0 -54
- data/spec/support/custom_json_serializer.rb +0 -13
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
module PaperTrail
|
|
4
|
-
::RSpec.describe Cleaner, versioning: true do
|
|
5
|
-
describe "clean_versions!" do
|
|
6
|
-
let(:animal) { ::Animal.new }
|
|
7
|
-
let(:dog) { ::Dog.new }
|
|
8
|
-
let(:cat) { ::Cat.new }
|
|
9
|
-
let(:animals) { [animal, dog, cat] }
|
|
10
|
-
|
|
11
|
-
before do
|
|
12
|
-
animals.each do |animal|
|
|
13
|
-
3.times do
|
|
14
|
-
animal.update_attribute(:name, FFaker::Name.name)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it "baseline test setup" do
|
|
20
|
-
expect(PaperTrail::Version.count).to(eq(9))
|
|
21
|
-
animals.each { |animal| expect(animal.versions.size).to(eq(3)) }
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
context "no options provided" do
|
|
25
|
-
it "removes extra versions for each item" do
|
|
26
|
-
PaperTrail.clean_versions!
|
|
27
|
-
expect(PaperTrail::Version.count).to(eq(3))
|
|
28
|
-
animals.each { |animal| expect(animal.versions.size).to(eq(1)) }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it "removes the earliest version(s)" do
|
|
32
|
-
before = animals.map { |animal| animal.versions.last.reify.name }
|
|
33
|
-
PaperTrail.clean_versions!
|
|
34
|
-
after = animals.map { |animal| animal.versions.last.reify.name }
|
|
35
|
-
expect(after).to(eq(before))
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
context "keeping 2" do
|
|
40
|
-
it "keeps two records, instead of the usual one" do
|
|
41
|
-
PaperTrail.clean_versions!(keeping: 2)
|
|
42
|
-
expect(PaperTrail::Version.all.count).to(eq(6))
|
|
43
|
-
animals.each { |animal| expect(animal.versions.size).to(eq(2)) }
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
context "with the :date option" do
|
|
48
|
-
it "only deletes versions created on the given date" do
|
|
49
|
-
animal.versions.each do |ver|
|
|
50
|
-
ver.update_attribute(:created_at, (ver.created_at - 1.day))
|
|
51
|
-
end
|
|
52
|
-
date = animal.versions.first.created_at.to_date
|
|
53
|
-
animal.update_attribute(:name, FFaker::Name.name)
|
|
54
|
-
expect(PaperTrail::Version.count).to(eq(10))
|
|
55
|
-
expect(animal.versions.size).to(eq(4))
|
|
56
|
-
expect(animal.paper_trail.versions_between(date, (date + 1.day)).size).to(eq(3))
|
|
57
|
-
PaperTrail.clean_versions!(date: date)
|
|
58
|
-
expect(PaperTrail::Version.count).to(eq(8))
|
|
59
|
-
expect(animal.versions.reload.size).to(eq(2))
|
|
60
|
-
expect(animal.versions.first.created_at.to_date).to(eq(date))
|
|
61
|
-
# Why use `equal?` here instead of something less strict?
|
|
62
|
-
# Doesn't `to_date` always produce a new date object?
|
|
63
|
-
expect(date.equal?(animal.versions.last.created_at.to_date)).to eq(false)
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
context "with the :item_id option" do
|
|
68
|
-
context "single ID received" do
|
|
69
|
-
it "only deletes the versions for the Item with that ID" do
|
|
70
|
-
PaperTrail.clean_versions!(item_id: animal.id)
|
|
71
|
-
expect(animal.versions.size).to(eq(1))
|
|
72
|
-
expect(PaperTrail::Version.count).to(eq(7))
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
context "collection of IDs received" do
|
|
77
|
-
it "only deletes versions for the Item(s) with those IDs" do
|
|
78
|
-
PaperTrail.clean_versions!(item_id: [animal.id, dog.id])
|
|
79
|
-
expect(animal.versions.size).to(eq(1))
|
|
80
|
-
expect(dog.versions.size).to(eq(1))
|
|
81
|
-
expect(PaperTrail::Version.count).to(eq(5))
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
context "options combinations" do
|
|
87
|
-
context ":date" do
|
|
88
|
-
before do
|
|
89
|
-
[animal, dog].each do |animal|
|
|
90
|
-
animal.versions.each do |ver|
|
|
91
|
-
ver.update_attribute(:created_at, (ver.created_at - 1.day))
|
|
92
|
-
end
|
|
93
|
-
animal.update_attribute(:name, FFaker::Name.name)
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
it "baseline test setup" do
|
|
98
|
-
date = animal.versions.first.created_at.to_date
|
|
99
|
-
expect(PaperTrail::Version.count).to(eq(11))
|
|
100
|
-
[animal, dog].each do |animal|
|
|
101
|
-
expect(animal.versions.size).to(eq(4))
|
|
102
|
-
expect(animal.versions.between(date, (date + 1.day)).size).to(eq(3))
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
context "and :keeping" do
|
|
107
|
-
it "restrict cleaning properly" do
|
|
108
|
-
date = animal.versions.first.created_at.to_date
|
|
109
|
-
PaperTrail.clean_versions!(date: date, keeping: 2)
|
|
110
|
-
[animal, dog].each do |animal|
|
|
111
|
-
animal.versions.reload
|
|
112
|
-
expect(animal.versions.size).to(eq(3))
|
|
113
|
-
expect(animal.versions.between(date, (date + 1.day)).size).to(eq(2))
|
|
114
|
-
end
|
|
115
|
-
expect(PaperTrail::Version.count).to(eq(9))
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
context "and :item_id" do
|
|
120
|
-
it "restrict cleaning properly" do
|
|
121
|
-
date = animal.versions.first.created_at.to_date
|
|
122
|
-
PaperTrail.clean_versions!(date: date, item_id: dog.id)
|
|
123
|
-
dog.versions.reload
|
|
124
|
-
expect(dog.versions.size).to(eq(2))
|
|
125
|
-
expect(dog.versions.between(date, (date + 1.day)).size).to(eq(1))
|
|
126
|
-
expect(PaperTrail::Version.count).to(eq(9))
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
context ", :item_id, and :keeping" do
|
|
131
|
-
it "restrict cleaning properly" do
|
|
132
|
-
date = animal.versions.first.created_at.to_date
|
|
133
|
-
PaperTrail.clean_versions!(date: date, item_id: dog.id, keeping: 2)
|
|
134
|
-
dog.versions.reload
|
|
135
|
-
expect(dog.versions.size).to(eq(3))
|
|
136
|
-
expect(dog.versions.between(date, (date + 1.day)).size).to(eq(2))
|
|
137
|
-
expect(PaperTrail::Version.count).to(eq(10))
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
context ":keeping and :item_id" do
|
|
143
|
-
it "restrict cleaning properly" do
|
|
144
|
-
PaperTrail.clean_versions!(keeping: 2, item_id: animal.id)
|
|
145
|
-
expect(animal.versions.size).to(eq(2))
|
|
146
|
-
expect(PaperTrail::Version.count).to(eq(8))
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
module PaperTrail
|
|
4
|
-
::RSpec.describe Config do
|
|
5
|
-
describe ".instance" do
|
|
6
|
-
it "returns the singleton instance" do
|
|
7
|
-
expect { described_class.instance }.not_to raise_error
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe ".new" do
|
|
12
|
-
it "raises NoMethodError" do
|
|
13
|
-
expect { described_class.new }.to raise_error(NoMethodError)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
describe "track_associations?" do
|
|
18
|
-
context "@track_associations is nil" do
|
|
19
|
-
after do
|
|
20
|
-
PaperTrail.config.track_associations = true
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it "returns false and prints a deprecation warning" do
|
|
24
|
-
config = described_class.instance
|
|
25
|
-
config.track_associations = nil
|
|
26
|
-
expect {
|
|
27
|
-
expect(config.track_associations?).to eq(false)
|
|
28
|
-
}.to output(/DEPRECATION WARNING/).to_stderr
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
describe ".version_limit", versioning: true do
|
|
34
|
-
after { PaperTrail.config.version_limit = nil }
|
|
35
|
-
|
|
36
|
-
it "limits the number of versions to 3 (2 plus the created at event)" do
|
|
37
|
-
PaperTrail.config.version_limit = 2
|
|
38
|
-
widget = Widget.create!(name: "Henry")
|
|
39
|
-
6.times { widget.update_attribute(:name, FFaker::Lorem.word) }
|
|
40
|
-
expect(widget.versions.first.event).to(eq("create"))
|
|
41
|
-
expect(widget.versions.size).to(eq(3))
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
@@ -1,992 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe(::PaperTrail, versioning: true) do
|
|
4
|
-
context "A new record" do
|
|
5
|
-
before { @widget = Widget.new }
|
|
6
|
-
|
|
7
|
-
it "not have any previous versions" do
|
|
8
|
-
expect(@widget.versions).to(eq([]))
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it "be live" do
|
|
12
|
-
expect(@widget.paper_trail.live?).to(eq(true))
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
context "which is then created" do
|
|
16
|
-
before do
|
|
17
|
-
@widget.update_attributes(name: "Henry", created_at: (Time.now - 1.day))
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it "have one previous version" do
|
|
21
|
-
expect(@widget.versions.length).to(eq(1))
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it "be nil in its previous version" do
|
|
25
|
-
expect(@widget.versions.first.object).to(be_nil)
|
|
26
|
-
expect(@widget.versions.first.reify).to(be_nil)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it "record the correct event" do
|
|
30
|
-
expect(@widget.versions.first.event).to(match(/create/i))
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it "be live" do
|
|
34
|
-
expect(@widget.paper_trail.live?).to(eq(true))
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it "use the widget `updated_at` as the version's `created_at`" do
|
|
38
|
-
expect(@widget.versions.first.created_at.to_i).to(eq(@widget.updated_at.to_i))
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
describe "#changeset" do
|
|
42
|
-
it "has expected values" do
|
|
43
|
-
changeset = @widget.versions.last.changeset
|
|
44
|
-
expect(changeset["name"]).to eq([nil, "Henry"])
|
|
45
|
-
expect(changeset["id"]).to eq([nil, @widget.id])
|
|
46
|
-
# When comparing timestamps, round off to the nearest second, because
|
|
47
|
-
# mysql doesn't do fractional seconds.
|
|
48
|
-
expect(changeset["created_at"][0]).to be_nil
|
|
49
|
-
expect(changeset["created_at"][1].to_i).to eq(@widget.created_at.to_i)
|
|
50
|
-
expect(changeset["updated_at"][0]).to be_nil
|
|
51
|
-
expect(changeset["updated_at"][1].to_i).to eq(@widget.updated_at.to_i)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
context "and then updated without any changes" do
|
|
56
|
-
before { @widget.touch }
|
|
57
|
-
|
|
58
|
-
it "not have a new version" do
|
|
59
|
-
expect(@widget.versions.length).to(eq(1))
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
context "and then updated with changes" do
|
|
64
|
-
before { @widget.update_attributes(name: "Harry") }
|
|
65
|
-
|
|
66
|
-
it "have two previous versions" do
|
|
67
|
-
expect(@widget.versions.length).to(eq(2))
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it "be available in its previous version" do
|
|
71
|
-
expect(@widget.name).to(eq("Harry"))
|
|
72
|
-
expect(@widget.versions.last.object).not_to(be_nil)
|
|
73
|
-
widget = @widget.versions.last.reify
|
|
74
|
-
expect(widget.name).to(eq("Henry"))
|
|
75
|
-
expect(@widget.name).to(eq("Harry"))
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
it "have the same ID in its previous version" do
|
|
79
|
-
expect(@widget.versions.last.reify.id).to(eq(@widget.id))
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
it "record the correct event" do
|
|
83
|
-
expect(@widget.versions.last.event).to(match(/update/i))
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it "have versions that are not live" do
|
|
87
|
-
expect(
|
|
88
|
-
@widget.versions.map(&:reify).compact.all? { |w| !w.paper_trail.live? }
|
|
89
|
-
).to(be_truthy)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it "have stored changes" do
|
|
93
|
-
last_obj_changes = @widget.versions.last.object_changes
|
|
94
|
-
actual = PaperTrail.serializer.load(last_obj_changes).reject do |k, _v|
|
|
95
|
-
(k.to_sym == :updated_at)
|
|
96
|
-
end
|
|
97
|
-
expect(actual).to(eq("name" => %w[Henry Harry]))
|
|
98
|
-
actual = @widget.versions.last.changeset.reject { |k, _v| (k.to_sym == :updated_at) }
|
|
99
|
-
expect(actual).to(eq("name" => %w[Henry Harry]))
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
it "return changes with indifferent access" do
|
|
103
|
-
expect(@widget.versions.last.changeset[:name]).to(eq(%w[Henry Harry]))
|
|
104
|
-
expect(@widget.versions.last.changeset["name"]).to(eq(%w[Henry Harry]))
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
context "and has one associated object" do
|
|
108
|
-
before { @wotsit = @widget.create_wotsit name: "John" }
|
|
109
|
-
|
|
110
|
-
it "not copy the has_one association by default when reifying" do
|
|
111
|
-
reified_widget = @widget.versions.last.reify
|
|
112
|
-
expect(reified_widget.wotsit).to(eq(@wotsit))
|
|
113
|
-
expect(@widget.reload.wotsit).to(eq(@wotsit))
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
it "copy the has_one association when reifying with :has_one => true" do
|
|
117
|
-
reified_widget = @widget.versions.last.reify(has_one: true)
|
|
118
|
-
expect(reified_widget.wotsit).to(be_nil)
|
|
119
|
-
expect(@widget.reload.wotsit).to(eq(@wotsit))
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
context "and has many associated objects" do
|
|
124
|
-
before do
|
|
125
|
-
@f0 = @widget.fluxors.create(name: "f-zero")
|
|
126
|
-
@f1 = @widget.fluxors.create(name: "f-one")
|
|
127
|
-
@reified_widget = @widget.versions.last.reify
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
it "copy the has_many associations when reifying" do
|
|
131
|
-
expect(@reified_widget.fluxors.length).to(eq(@widget.fluxors.length))
|
|
132
|
-
expect(@reified_widget.fluxors).to match_array(@widget.fluxors)
|
|
133
|
-
expect(@reified_widget.versions.length).to(eq(@widget.versions.length))
|
|
134
|
-
expect(@reified_widget.versions).to match_array(@widget.versions)
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
context "and has many associated polymorphic objects" do
|
|
139
|
-
before do
|
|
140
|
-
@f0 = @widget.whatchamajiggers.create(name: "f-zero")
|
|
141
|
-
@f1 = @widget.whatchamajiggers.create(name: "f-zero")
|
|
142
|
-
@reified_widget = @widget.versions.last.reify
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
it "copy the has_many associations when reifying" do
|
|
146
|
-
expect(@reified_widget.whatchamajiggers.length).to eq(@widget.whatchamajiggers.length)
|
|
147
|
-
expect(@reified_widget.whatchamajiggers).to match_array(@widget.whatchamajiggers)
|
|
148
|
-
expect(@reified_widget.versions.length).to(eq(@widget.versions.length))
|
|
149
|
-
expect(@reified_widget.versions).to match_array(@widget.versions)
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
context "polymorphic objects by themselves" do
|
|
154
|
-
before { @widget = Whatchamajigger.new(name: "f-zero") }
|
|
155
|
-
|
|
156
|
-
it "not fail with a nil pointer on the polymorphic association" do
|
|
157
|
-
@widget.save!
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
context "and then destroyed" do
|
|
162
|
-
before do
|
|
163
|
-
@fluxor = @widget.fluxors.create(name: "flux")
|
|
164
|
-
@widget.destroy
|
|
165
|
-
@reified_widget = PaperTrail::Version.last.reify
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
it "record the correct event" do
|
|
169
|
-
expect(PaperTrail::Version.last.event).to(match(/destroy/i))
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
it "have three previous versions" do
|
|
173
|
-
expect(PaperTrail::Version.with_item_keys("Widget", @widget.id).length).to(eq(3))
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
describe "#attributes" do
|
|
177
|
-
it "returns the expected attributes for the reified widget" do
|
|
178
|
-
expect(@reified_widget.id).to(eq(@widget.id))
|
|
179
|
-
expected = @widget.attributes
|
|
180
|
-
actual = @reified_widget.attributes
|
|
181
|
-
expect(expected["id"]).to eq(actual["id"])
|
|
182
|
-
expect(expected["name"]).to eq(actual["name"])
|
|
183
|
-
expect(expected["a_text"]).to eq(actual["a_text"])
|
|
184
|
-
expect(expected["an_integer"]).to eq(actual["an_integer"])
|
|
185
|
-
expect(expected["a_float"]).to eq(actual["a_float"])
|
|
186
|
-
expect(expected["a_decimal"]).to eq(actual["a_decimal"])
|
|
187
|
-
expect(expected["a_datetime"]).to eq(actual["a_datetime"])
|
|
188
|
-
expect(expected["a_time"]).to eq(actual["a_time"])
|
|
189
|
-
expect(expected["a_date"]).to eq(actual["a_date"])
|
|
190
|
-
expect(expected["a_boolean"]).to eq(actual["a_boolean"])
|
|
191
|
-
expect(expected["type"]).to eq(actual["type"])
|
|
192
|
-
expect(expected["created_at"].to_i).to eq(actual["created_at"].to_i)
|
|
193
|
-
expect(expected["updated_at"].to_i).to eq(actual["updated_at"].to_i)
|
|
194
|
-
end
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
it "be re-creatable from its previous version" do
|
|
198
|
-
expect(@reified_widget.save).to(be_truthy)
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
it "restore its associations on its previous version" do
|
|
202
|
-
@reified_widget.save
|
|
203
|
-
expect(@reified_widget.fluxors.length).to(eq(1))
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
it "have nil item for last version" do
|
|
207
|
-
expect(@widget.versions.last.item).to(be_nil)
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
it "not have changes" do
|
|
211
|
-
expect(@widget.versions.last.changeset).to(eq({}))
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
context "A record's papertrail" do
|
|
219
|
-
before do
|
|
220
|
-
@date_time = DateTime.now.utc
|
|
221
|
-
@time = Time.now
|
|
222
|
-
@date = Date.new(2009, 5, 29)
|
|
223
|
-
@widget = Widget.create(
|
|
224
|
-
name: "Warble",
|
|
225
|
-
a_text: "The quick brown fox",
|
|
226
|
-
an_integer: 42,
|
|
227
|
-
a_float: 153.01,
|
|
228
|
-
a_decimal: 2.71828,
|
|
229
|
-
a_datetime: @date_time,
|
|
230
|
-
a_time: @time,
|
|
231
|
-
a_date: @date,
|
|
232
|
-
a_boolean: true
|
|
233
|
-
)
|
|
234
|
-
@widget.update_attributes(
|
|
235
|
-
name: nil,
|
|
236
|
-
a_text: nil,
|
|
237
|
-
an_integer: nil,
|
|
238
|
-
a_float: nil,
|
|
239
|
-
a_decimal: nil,
|
|
240
|
-
a_datetime: nil,
|
|
241
|
-
a_time: nil,
|
|
242
|
-
a_date: nil,
|
|
243
|
-
a_boolean: false
|
|
244
|
-
)
|
|
245
|
-
@previous = @widget.versions.last.reify
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
it "handle strings" do
|
|
249
|
-
expect(@previous.name).to(eq("Warble"))
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
it "handle text" do
|
|
253
|
-
expect(@previous.a_text).to(eq("The quick brown fox"))
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
it "handle integers" do
|
|
257
|
-
expect(@previous.an_integer).to(eq(42))
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
it "handle floats" do
|
|
261
|
-
assert_in_delta(153.01, @previous.a_float, 0.001)
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
it "handle decimals" do
|
|
265
|
-
assert_in_delta(2.7183, @previous.a_decimal, 0.0001)
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
it "handle datetimes" do
|
|
269
|
-
expect(@previous.a_datetime.to_time.utc.to_i).to(eq(@date_time.to_time.utc.to_i))
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
it "handle times" do
|
|
273
|
-
expect(@previous.a_time.utc.to_i).to(eq(@time.utc.to_i))
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
it "handle dates" do
|
|
277
|
-
expect(@previous.a_date).to(eq(@date))
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
it "handle booleans" do
|
|
281
|
-
expect(@previous.a_boolean).to(be_truthy)
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
context "after a column is removed from the record's schema" do
|
|
285
|
-
before { @last = @widget.versions.last }
|
|
286
|
-
|
|
287
|
-
it "reify previous version" do
|
|
288
|
-
assert_kind_of(Widget, @last.reify)
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
it "restore all forward-compatible attributes" do
|
|
292
|
-
expect(@last.reify.name).to(eq("Warble"))
|
|
293
|
-
expect(@last.reify.a_text).to(eq("The quick brown fox"))
|
|
294
|
-
expect(@last.reify.an_integer).to(eq(42))
|
|
295
|
-
assert_in_delta(153.01, @last.reify.a_float, 0.001)
|
|
296
|
-
assert_in_delta(2.7183, @last.reify.a_decimal, 0.0001)
|
|
297
|
-
expect(@last.reify.a_datetime.to_time.utc.to_i).to(eq(@date_time.to_time.utc.to_i))
|
|
298
|
-
expect(@last.reify.a_time.utc.to_i).to(eq(@time.utc.to_i))
|
|
299
|
-
expect(@last.reify.a_date).to(eq(@date))
|
|
300
|
-
expect(@last.reify.a_boolean).to(be_truthy)
|
|
301
|
-
end
|
|
302
|
-
end
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
context "A record" do
|
|
306
|
-
before { @widget = Widget.create(name: "Zaphod") }
|
|
307
|
-
|
|
308
|
-
context "with PaperTrail globally disabled" do
|
|
309
|
-
before do
|
|
310
|
-
PaperTrail.enabled = false
|
|
311
|
-
@count = @widget.versions.length
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
after { PaperTrail.enabled = true }
|
|
315
|
-
|
|
316
|
-
context "when updated" do
|
|
317
|
-
before { @widget.update_attributes(name: "Beeblebrox") }
|
|
318
|
-
|
|
319
|
-
it "not add to its trail" do
|
|
320
|
-
expect(@widget.versions.length).to(eq(@count))
|
|
321
|
-
end
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
context "with its paper trail turned off" do
|
|
326
|
-
before do
|
|
327
|
-
Widget.paper_trail.disable
|
|
328
|
-
@count = @widget.versions.length
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
after { Widget.paper_trail.enable }
|
|
332
|
-
|
|
333
|
-
context "when updated" do
|
|
334
|
-
before { @widget.update_attributes(name: "Beeblebrox") }
|
|
335
|
-
|
|
336
|
-
it "not add to its trail" do
|
|
337
|
-
expect(@widget.versions.length).to(eq(@count))
|
|
338
|
-
end
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
context "when destroyed \"without versioning\"" do
|
|
342
|
-
it "leave paper trail off after call" do
|
|
343
|
-
@widget.paper_trail.without_versioning(:destroy)
|
|
344
|
-
expect(Widget.paper_trail.enabled?).to(eq(false))
|
|
345
|
-
end
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
context "and then its paper trail turned on" do
|
|
349
|
-
before { Widget.paper_trail.enable }
|
|
350
|
-
|
|
351
|
-
context "when updated" do
|
|
352
|
-
before { @widget.update_attributes(name: "Ford") }
|
|
353
|
-
|
|
354
|
-
it "add to its trail" do
|
|
355
|
-
expect(@widget.versions.length).to(eq((@count + 1)))
|
|
356
|
-
end
|
|
357
|
-
end
|
|
358
|
-
|
|
359
|
-
context "when updated \"without versioning\"" do
|
|
360
|
-
before do
|
|
361
|
-
@widget.paper_trail.without_versioning do
|
|
362
|
-
@widget.update_attributes(name: "Ford")
|
|
363
|
-
end
|
|
364
|
-
@widget.paper_trail.without_versioning do |w|
|
|
365
|
-
w.update_attributes(name: "Nixon")
|
|
366
|
-
end
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
it "not create new version" do
|
|
370
|
-
expect(@widget.versions.length).to(eq(@count))
|
|
371
|
-
end
|
|
372
|
-
|
|
373
|
-
it "enable paper trail after call" do
|
|
374
|
-
expect(Widget.paper_trail.enabled?).to(eq(true))
|
|
375
|
-
end
|
|
376
|
-
end
|
|
377
|
-
|
|
378
|
-
context "when receiving a method name as an argument" do
|
|
379
|
-
before { @widget.paper_trail.without_versioning(:touch_with_version) }
|
|
380
|
-
|
|
381
|
-
it "not create new version" do
|
|
382
|
-
expect(@widget.versions.length).to(eq(@count))
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
it "enable paper trail after call" do
|
|
386
|
-
expect(Widget.paper_trail.enabled?).to(eq(true))
|
|
387
|
-
end
|
|
388
|
-
end
|
|
389
|
-
end
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
context "A papertrail with somebody making changes" do
|
|
394
|
-
before { @widget = Widget.new(name: "Fidget") }
|
|
395
|
-
|
|
396
|
-
context "when a record is created" do
|
|
397
|
-
before do
|
|
398
|
-
PaperTrail.whodunnit = "Alice"
|
|
399
|
-
@widget.save
|
|
400
|
-
@version = @widget.versions.last
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
it "track who made the change" do
|
|
404
|
-
expect(@version.whodunnit).to(eq("Alice"))
|
|
405
|
-
expect(@version.paper_trail_originator).to(be_nil)
|
|
406
|
-
expect(@version.terminator).to(eq("Alice"))
|
|
407
|
-
expect(@widget.paper_trail.originator).to(eq("Alice"))
|
|
408
|
-
end
|
|
409
|
-
|
|
410
|
-
context "when a record is updated" do
|
|
411
|
-
before do
|
|
412
|
-
PaperTrail.whodunnit = "Bob"
|
|
413
|
-
@widget.update_attributes(name: "Rivet")
|
|
414
|
-
@version = @widget.versions.last
|
|
415
|
-
end
|
|
416
|
-
|
|
417
|
-
it "track who made the change" do
|
|
418
|
-
expect(@version.whodunnit).to(eq("Bob"))
|
|
419
|
-
expect(@version.paper_trail_originator).to(eq("Alice"))
|
|
420
|
-
expect(@version.terminator).to(eq("Bob"))
|
|
421
|
-
expect(@widget.paper_trail.originator).to(eq("Bob"))
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
context "when a record is destroyed" do
|
|
425
|
-
before do
|
|
426
|
-
PaperTrail.whodunnit = "Charlie"
|
|
427
|
-
@widget.destroy
|
|
428
|
-
@version = PaperTrail::Version.last
|
|
429
|
-
end
|
|
430
|
-
|
|
431
|
-
it "track who made the change" do
|
|
432
|
-
expect(@version.whodunnit).to(eq("Charlie"))
|
|
433
|
-
expect(@version.paper_trail_originator).to(eq("Bob"))
|
|
434
|
-
expect(@version.terminator).to(eq("Charlie"))
|
|
435
|
-
expect(@widget.paper_trail.originator).to(eq("Charlie"))
|
|
436
|
-
end
|
|
437
|
-
end
|
|
438
|
-
end
|
|
439
|
-
end
|
|
440
|
-
end
|
|
441
|
-
|
|
442
|
-
it "update_attributes! records timestamps" do
|
|
443
|
-
wotsit = Wotsit.create!(name: "wotsit")
|
|
444
|
-
wotsit.update_attributes!(name: "changed")
|
|
445
|
-
reified = wotsit.versions.last.reify
|
|
446
|
-
expect(reified.created_at).not_to(be_nil)
|
|
447
|
-
expect(reified.updated_at).not_to(be_nil)
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
it "update_attributes! does not raise error" do
|
|
451
|
-
wotsit = Wotsit.create!(name: "name1")
|
|
452
|
-
expect { wotsit.update_attributes!(name: "name2") }.not_to(raise_error)
|
|
453
|
-
end
|
|
454
|
-
|
|
455
|
-
context "A subclass" do
|
|
456
|
-
before do
|
|
457
|
-
@foo = FooWidget.create
|
|
458
|
-
@foo.update_attributes!(name: "Foo")
|
|
459
|
-
end
|
|
460
|
-
|
|
461
|
-
it "reify with the correct type" do
|
|
462
|
-
if ActiveRecord::VERSION::MAJOR < 4
|
|
463
|
-
assert_kind_of(FooWidget, @foo.versions.last.reify)
|
|
464
|
-
end
|
|
465
|
-
expect(PaperTrail::Version.last.previous).to(eq(@foo.versions.first))
|
|
466
|
-
expect(PaperTrail::Version.last.next).to(be_nil)
|
|
467
|
-
end
|
|
468
|
-
|
|
469
|
-
it "returns the correct originator" do
|
|
470
|
-
PaperTrail.whodunnit = "Ben"
|
|
471
|
-
@foo.update_attribute(:name, "Geoffrey")
|
|
472
|
-
expect(@foo.paper_trail.originator).to(eq(PaperTrail.whodunnit))
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
context "when destroyed" do
|
|
476
|
-
before { @foo.destroy }
|
|
477
|
-
|
|
478
|
-
it "reify with the correct type" do
|
|
479
|
-
assert_kind_of(FooWidget, @foo.versions.last.reify)
|
|
480
|
-
expect(PaperTrail::Version.last.previous).to(eq(@foo.versions[1]))
|
|
481
|
-
expect(PaperTrail::Version.last.next).to(be_nil)
|
|
482
|
-
end
|
|
483
|
-
end
|
|
484
|
-
end
|
|
485
|
-
|
|
486
|
-
context "An item with versions" do
|
|
487
|
-
before do
|
|
488
|
-
@widget = Widget.create(name: "Widget")
|
|
489
|
-
@widget.update_attributes(name: "Fidget")
|
|
490
|
-
@widget.update_attributes(name: "Digit")
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
context "which were created over time" do
|
|
494
|
-
before do
|
|
495
|
-
@created = 2.days.ago
|
|
496
|
-
@first_update = 1.day.ago
|
|
497
|
-
@second_update = 1.hour.ago
|
|
498
|
-
@widget.versions[0].update_attributes(created_at: @created)
|
|
499
|
-
@widget.versions[1].update_attributes(created_at: @first_update)
|
|
500
|
-
@widget.versions[2].update_attributes(created_at: @second_update)
|
|
501
|
-
@widget.update_attribute(:updated_at, @second_update)
|
|
502
|
-
end
|
|
503
|
-
|
|
504
|
-
it "return nil for version_at before it was created" do
|
|
505
|
-
expect(@widget.paper_trail.version_at((@created - 1))).to(be_nil)
|
|
506
|
-
end
|
|
507
|
-
|
|
508
|
-
it "return how it looked when created for version_at its creation" do
|
|
509
|
-
expect(@widget.paper_trail.version_at(@created).name).to(eq("Widget"))
|
|
510
|
-
end
|
|
511
|
-
|
|
512
|
-
it "return how it looked before its first update" do
|
|
513
|
-
expect(@widget.paper_trail.version_at((@first_update - 1)).name).to(eq("Widget"))
|
|
514
|
-
end
|
|
515
|
-
|
|
516
|
-
it "return how it looked after its first update" do
|
|
517
|
-
expect(@widget.paper_trail.version_at(@first_update).name).to(eq("Fidget"))
|
|
518
|
-
end
|
|
519
|
-
|
|
520
|
-
it "return how it looked before its second update" do
|
|
521
|
-
expect(@widget.paper_trail.version_at((@second_update - 1)).name).to(eq("Fidget"))
|
|
522
|
-
end
|
|
523
|
-
|
|
524
|
-
it "return how it looked after its second update" do
|
|
525
|
-
expect(@widget.paper_trail.version_at(@second_update).name).to(eq("Digit"))
|
|
526
|
-
end
|
|
527
|
-
|
|
528
|
-
it "return the current object for version_at after latest update" do
|
|
529
|
-
expect(@widget.paper_trail.version_at(1.day.from_now).name).to(eq("Digit"))
|
|
530
|
-
end
|
|
531
|
-
|
|
532
|
-
context "passing in a string representation of a timestamp" do
|
|
533
|
-
it "still return a widget when appropriate" do
|
|
534
|
-
expect(
|
|
535
|
-
@widget.paper_trail.version_at((@created + 1.second).to_s).name
|
|
536
|
-
).to(eq("Widget"))
|
|
537
|
-
expect(
|
|
538
|
-
@widget.paper_trail.version_at((@first_update + 1.second).to_s).name
|
|
539
|
-
).to(eq("Fidget"))
|
|
540
|
-
expect(
|
|
541
|
-
@widget.paper_trail.version_at((@second_update + 1.second).to_s).name
|
|
542
|
-
).to(eq("Digit"))
|
|
543
|
-
end
|
|
544
|
-
end
|
|
545
|
-
end
|
|
546
|
-
|
|
547
|
-
context ".versions_between" do
|
|
548
|
-
before do
|
|
549
|
-
@created = 30.days.ago
|
|
550
|
-
@first_update = 15.days.ago
|
|
551
|
-
@second_update = 1.day.ago
|
|
552
|
-
@widget.versions[0].update_attributes(created_at: @created)
|
|
553
|
-
@widget.versions[1].update_attributes(created_at: @first_update)
|
|
554
|
-
@widget.versions[2].update_attributes(created_at: @second_update)
|
|
555
|
-
@widget.update_attribute(:updated_at, @second_update)
|
|
556
|
-
end
|
|
557
|
-
|
|
558
|
-
it "return versions in the time period" do
|
|
559
|
-
expect(
|
|
560
|
-
@widget.paper_trail.versions_between(20.days.ago, 10.days.ago).map(&:name)
|
|
561
|
-
).to(eq(["Fidget"]))
|
|
562
|
-
expect(
|
|
563
|
-
@widget.paper_trail.versions_between(45.days.ago, 10.days.ago).map(&:name)
|
|
564
|
-
).to(eq(%w[Widget Fidget]))
|
|
565
|
-
expect(
|
|
566
|
-
@widget.paper_trail.versions_between(16.days.ago, 1.minute.ago).map(&:name)
|
|
567
|
-
).to(eq(%w[Fidget Digit Digit]))
|
|
568
|
-
expect(
|
|
569
|
-
@widget.paper_trail.versions_between(60.days.ago, 45.days.ago).map(&:name)
|
|
570
|
-
).to(eq([]))
|
|
571
|
-
end
|
|
572
|
-
end
|
|
573
|
-
|
|
574
|
-
context "on the first version" do
|
|
575
|
-
before { @version = @widget.versions.first }
|
|
576
|
-
|
|
577
|
-
it "have a nil previous version" do
|
|
578
|
-
expect(@version.previous).to(be_nil)
|
|
579
|
-
end
|
|
580
|
-
|
|
581
|
-
it "return the next version" do
|
|
582
|
-
expect(@version.next).to(eq(@widget.versions[1]))
|
|
583
|
-
end
|
|
584
|
-
|
|
585
|
-
it "return the correct index" do
|
|
586
|
-
expect(@version.index).to(eq(0))
|
|
587
|
-
end
|
|
588
|
-
end
|
|
589
|
-
|
|
590
|
-
context "on the last version" do
|
|
591
|
-
before { @version = @widget.versions.last }
|
|
592
|
-
|
|
593
|
-
it "return the previous version" do
|
|
594
|
-
expect(@version.previous).to(eq(@widget.versions[(@widget.versions.length - 2)]))
|
|
595
|
-
end
|
|
596
|
-
|
|
597
|
-
it "have a nil next version" do
|
|
598
|
-
expect(@version.next).to(be_nil)
|
|
599
|
-
end
|
|
600
|
-
|
|
601
|
-
it "return the correct index" do
|
|
602
|
-
expect(@version.index).to(eq((@widget.versions.length - 1)))
|
|
603
|
-
end
|
|
604
|
-
end
|
|
605
|
-
end
|
|
606
|
-
|
|
607
|
-
context "An item" do
|
|
608
|
-
before do
|
|
609
|
-
@initial_title = "Foobar"
|
|
610
|
-
@article = Article.new(title: @initial_title)
|
|
611
|
-
end
|
|
612
|
-
|
|
613
|
-
context "which is created" do
|
|
614
|
-
before { @article.save }
|
|
615
|
-
|
|
616
|
-
it "store fixed meta data" do
|
|
617
|
-
expect(@article.versions.last.answer).to(eq(42))
|
|
618
|
-
end
|
|
619
|
-
|
|
620
|
-
it "store dynamic meta data which is independent of the item" do
|
|
621
|
-
expect(@article.versions.last.question).to(eq("31 + 11 = 42"))
|
|
622
|
-
end
|
|
623
|
-
|
|
624
|
-
it "store dynamic meta data which depends on the item" do
|
|
625
|
-
expect(@article.versions.last.article_id).to(eq(@article.id))
|
|
626
|
-
end
|
|
627
|
-
|
|
628
|
-
it "store dynamic meta data based on a method of the item" do
|
|
629
|
-
expect(@article.versions.last.action).to(eq(@article.action_data_provider_method))
|
|
630
|
-
end
|
|
631
|
-
|
|
632
|
-
it "store dynamic meta data based on an attribute of the item at creation" do
|
|
633
|
-
expect(@article.versions.last.title).to(eq(@initial_title))
|
|
634
|
-
end
|
|
635
|
-
|
|
636
|
-
context "and updated" do
|
|
637
|
-
before do
|
|
638
|
-
@article.update_attributes!(content: "Better text.", title: "Rhubarb")
|
|
639
|
-
end
|
|
640
|
-
|
|
641
|
-
it "store fixed meta data" do
|
|
642
|
-
expect(@article.versions.last.answer).to(eq(42))
|
|
643
|
-
end
|
|
644
|
-
|
|
645
|
-
it "store dynamic meta data which is independent of the item" do
|
|
646
|
-
expect(@article.versions.last.question).to(eq("31 + 11 = 42"))
|
|
647
|
-
end
|
|
648
|
-
|
|
649
|
-
it "store dynamic meta data which depends on the item" do
|
|
650
|
-
expect(@article.versions.last.article_id).to(eq(@article.id))
|
|
651
|
-
end
|
|
652
|
-
|
|
653
|
-
it "store dynamic meta data based on an attribute of the item prior to the update" do
|
|
654
|
-
expect(@article.versions.last.title).to(eq(@initial_title))
|
|
655
|
-
end
|
|
656
|
-
end
|
|
657
|
-
|
|
658
|
-
context "and destroyed" do
|
|
659
|
-
before { @article.destroy }
|
|
660
|
-
|
|
661
|
-
it "store fixed metadata" do
|
|
662
|
-
expect(@article.versions.last.answer).to(eq(42))
|
|
663
|
-
end
|
|
664
|
-
|
|
665
|
-
it "store dynamic metadata which is independent of the item" do
|
|
666
|
-
expect(@article.versions.last.question).to(eq("31 + 11 = 42"))
|
|
667
|
-
end
|
|
668
|
-
|
|
669
|
-
it "store dynamic metadata which depends on the item" do
|
|
670
|
-
expect(@article.versions.last.article_id).to(eq(@article.id))
|
|
671
|
-
end
|
|
672
|
-
|
|
673
|
-
it "store dynamic metadata based on attribute of item prior to destruction" do
|
|
674
|
-
expect(@article.versions.last.title).to(eq(@initial_title))
|
|
675
|
-
end
|
|
676
|
-
end
|
|
677
|
-
end
|
|
678
|
-
end
|
|
679
|
-
|
|
680
|
-
context "A reified item" do
|
|
681
|
-
before do
|
|
682
|
-
widget = Widget.create(name: "Bob")
|
|
683
|
-
%w[Tom Dick Jane].each do |name|
|
|
684
|
-
widget.update_attributes(name: name)
|
|
685
|
-
end
|
|
686
|
-
@version = widget.versions.last
|
|
687
|
-
@widget = @version.reify
|
|
688
|
-
end
|
|
689
|
-
|
|
690
|
-
it "know which version it came from" do
|
|
691
|
-
expect(@widget.version).to(eq(@version))
|
|
692
|
-
end
|
|
693
|
-
|
|
694
|
-
it "return its previous self" do
|
|
695
|
-
expect(@widget.paper_trail.previous_version).to(eq(@widget.versions[-2].reify))
|
|
696
|
-
end
|
|
697
|
-
end
|
|
698
|
-
|
|
699
|
-
context "A non-reified item" do
|
|
700
|
-
before { @widget = Widget.new }
|
|
701
|
-
|
|
702
|
-
it "not have a previous version" do
|
|
703
|
-
expect(@widget.paper_trail.previous_version).to(be_nil)
|
|
704
|
-
end
|
|
705
|
-
|
|
706
|
-
it "not have a next version" do
|
|
707
|
-
expect(@widget.paper_trail.next_version).to(be_nil)
|
|
708
|
-
end
|
|
709
|
-
|
|
710
|
-
context "with versions" do
|
|
711
|
-
before do
|
|
712
|
-
@widget.save
|
|
713
|
-
%w[Tom Dick Jane].each do |name|
|
|
714
|
-
@widget.update_attributes(name: name)
|
|
715
|
-
end
|
|
716
|
-
end
|
|
717
|
-
|
|
718
|
-
it "have a previous version" do
|
|
719
|
-
expect(@widget.paper_trail.previous_version.name).to(eq(@widget.versions.last.reify.name))
|
|
720
|
-
end
|
|
721
|
-
|
|
722
|
-
it "not have a next version" do
|
|
723
|
-
expect(@widget.paper_trail.next_version).to(be_nil)
|
|
724
|
-
end
|
|
725
|
-
end
|
|
726
|
-
end
|
|
727
|
-
|
|
728
|
-
context "A reified item" do
|
|
729
|
-
before do
|
|
730
|
-
@widget = Widget.create(name: "Bob")
|
|
731
|
-
%w[Tom Dick Jane].each do |name|
|
|
732
|
-
@widget.update_attributes(name: name)
|
|
733
|
-
end
|
|
734
|
-
@second_widget = @widget.versions[1].reify
|
|
735
|
-
@last_widget = @widget.versions.last.reify
|
|
736
|
-
end
|
|
737
|
-
|
|
738
|
-
it "have a previous version" do
|
|
739
|
-
expect(@second_widget.paper_trail.previous_version).to(be_nil)
|
|
740
|
-
expect(@last_widget.paper_trail.previous_version.name).to(eq(@widget.versions[-2].reify.name))
|
|
741
|
-
end
|
|
742
|
-
|
|
743
|
-
it "have a next version" do
|
|
744
|
-
expect(@second_widget.paper_trail.next_version.name).to(eq(@widget.versions[2].reify.name))
|
|
745
|
-
expect(@widget.name).to(eq(@last_widget.paper_trail.next_version.name))
|
|
746
|
-
end
|
|
747
|
-
end
|
|
748
|
-
|
|
749
|
-
context ":has_many :through" do
|
|
750
|
-
before do
|
|
751
|
-
@book = Book.create(title: "War and Peace")
|
|
752
|
-
@dostoyevsky = Person.create(name: "Dostoyevsky")
|
|
753
|
-
@solzhenitsyn = Person.create(name: "Solzhenitsyn")
|
|
754
|
-
end
|
|
755
|
-
|
|
756
|
-
it "store version on source <<" do
|
|
757
|
-
count = PaperTrail::Version.count
|
|
758
|
-
(@book.authors << @dostoyevsky)
|
|
759
|
-
expect((PaperTrail::Version.count - count)).to(eq(1))
|
|
760
|
-
expect(@book.authorships.first.versions.first).to(eq(PaperTrail::Version.last))
|
|
761
|
-
end
|
|
762
|
-
|
|
763
|
-
it "store version on source create" do
|
|
764
|
-
count = PaperTrail::Version.count
|
|
765
|
-
@book.authors.create(name: "Tolstoy")
|
|
766
|
-
expect((PaperTrail::Version.count - count)).to(eq(2))
|
|
767
|
-
expect(
|
|
768
|
-
[PaperTrail::Version.order(:id).to_a[-2].item, PaperTrail::Version.last.item]
|
|
769
|
-
).to match_array([Person.last, Authorship.last])
|
|
770
|
-
end
|
|
771
|
-
|
|
772
|
-
it "store version on join destroy" do
|
|
773
|
-
(@book.authors << @dostoyevsky)
|
|
774
|
-
count = PaperTrail::Version.count
|
|
775
|
-
@book.authorships.reload.last.destroy
|
|
776
|
-
expect((PaperTrail::Version.count - count)).to(eq(1))
|
|
777
|
-
expect(PaperTrail::Version.last.reify.book).to(eq(@book))
|
|
778
|
-
expect(PaperTrail::Version.last.reify.author).to(eq(@dostoyevsky))
|
|
779
|
-
end
|
|
780
|
-
|
|
781
|
-
it "store version on join clear" do
|
|
782
|
-
(@book.authors << @dostoyevsky)
|
|
783
|
-
count = PaperTrail::Version.count
|
|
784
|
-
@book.authorships.reload.destroy_all
|
|
785
|
-
expect((PaperTrail::Version.count - count)).to(eq(1))
|
|
786
|
-
expect(PaperTrail::Version.last.reify.book).to(eq(@book))
|
|
787
|
-
expect(PaperTrail::Version.last.reify.author).to(eq(@dostoyevsky))
|
|
788
|
-
end
|
|
789
|
-
end
|
|
790
|
-
|
|
791
|
-
context "When an attribute has a custom serializer" do
|
|
792
|
-
before { @person = Person.new(time_zone: "Samoa") }
|
|
793
|
-
|
|
794
|
-
it "be an instance of ActiveSupport::TimeZone" do
|
|
795
|
-
expect(@person.time_zone.class).to(eq(ActiveSupport::TimeZone))
|
|
796
|
-
end
|
|
797
|
-
|
|
798
|
-
context "when the model is saved" do
|
|
799
|
-
before do
|
|
800
|
-
@changes_before_save = @person.changes.dup
|
|
801
|
-
@person.save!
|
|
802
|
-
end
|
|
803
|
-
|
|
804
|
-
it "version.object_changes should store long serialization of TimeZone object" do
|
|
805
|
-
len = @person.versions.last.object_changes.length
|
|
806
|
-
expect((len < 105)).to(be_truthy)
|
|
807
|
-
end
|
|
808
|
-
|
|
809
|
-
it "version.object_changes attribute should have stored the value from serializer" do
|
|
810
|
-
as_stored_in_version = HashWithIndifferentAccess[
|
|
811
|
-
YAML.load(@person.versions.last.object_changes)
|
|
812
|
-
]
|
|
813
|
-
expect(as_stored_in_version[:time_zone]).to(eq([nil, "Samoa"]))
|
|
814
|
-
serialized_value = Person::TimeZoneSerializer.dump(@person.time_zone)
|
|
815
|
-
expect(as_stored_in_version[:time_zone].last).to(eq(serialized_value))
|
|
816
|
-
end
|
|
817
|
-
|
|
818
|
-
it "version.changeset should convert attribute to original, unserialized value" do
|
|
819
|
-
unserialized_value = Person::TimeZoneSerializer.load(@person.time_zone)
|
|
820
|
-
expect(@person.versions.last.changeset[:time_zone].last).to(eq(unserialized_value))
|
|
821
|
-
end
|
|
822
|
-
|
|
823
|
-
it "record.changes (before save) returns the original, unserialized values" do
|
|
824
|
-
expect(
|
|
825
|
-
@changes_before_save[:time_zone].map(&:class)
|
|
826
|
-
).to(eq([NilClass, ActiveSupport::TimeZone]))
|
|
827
|
-
end
|
|
828
|
-
|
|
829
|
-
it "version.changeset should be the same as record.changes was before the save" do
|
|
830
|
-
actual = @person.versions.last.changeset.delete_if { |k, _v| (k.to_sym == :id) }
|
|
831
|
-
expect(actual).to(eq(@changes_before_save))
|
|
832
|
-
actual = @person.versions.last.changeset[:time_zone].map(&:class)
|
|
833
|
-
expect(actual).to(eq([NilClass, ActiveSupport::TimeZone]))
|
|
834
|
-
end
|
|
835
|
-
|
|
836
|
-
context "when that attribute is updated" do
|
|
837
|
-
before do
|
|
838
|
-
@attribute_value_before_change = @person.time_zone
|
|
839
|
-
@person.assign_attributes(time_zone: "Pacific Time (US & Canada)")
|
|
840
|
-
@changes_before_save = @person.changes.dup
|
|
841
|
-
@person.save!
|
|
842
|
-
end
|
|
843
|
-
|
|
844
|
-
it "object should not store long serialization of TimeZone object" do
|
|
845
|
-
len = @person.versions.last.object.length
|
|
846
|
-
expect((len < 105)).to(be_truthy)
|
|
847
|
-
end
|
|
848
|
-
|
|
849
|
-
it "object_changes should not store long serialization of TimeZone object" do
|
|
850
|
-
max_len = ActiveRecord::VERSION::MAJOR < 4 ? 105 : 118
|
|
851
|
-
len = @person.versions.last.object_changes.length
|
|
852
|
-
expect((len < max_len)).to(be_truthy)
|
|
853
|
-
end
|
|
854
|
-
|
|
855
|
-
it "version.object attribute should have stored value from serializer" do
|
|
856
|
-
as_stored_in_version = HashWithIndifferentAccess[
|
|
857
|
-
YAML.load(@person.versions.last.object)
|
|
858
|
-
]
|
|
859
|
-
expect(as_stored_in_version[:time_zone]).to(eq("Samoa"))
|
|
860
|
-
serialized_value = Person::TimeZoneSerializer.dump(@attribute_value_before_change)
|
|
861
|
-
expect(as_stored_in_version[:time_zone]).to(eq(serialized_value))
|
|
862
|
-
end
|
|
863
|
-
|
|
864
|
-
it "version.object_changes attribute should have stored value from serializer" do
|
|
865
|
-
as_stored_in_version = HashWithIndifferentAccess[
|
|
866
|
-
YAML.load(@person.versions.last.object_changes)
|
|
867
|
-
]
|
|
868
|
-
expect(as_stored_in_version[:time_zone]).to(eq(["Samoa", "Pacific Time (US & Canada)"]))
|
|
869
|
-
serialized_value = Person::TimeZoneSerializer.dump(@person.time_zone)
|
|
870
|
-
expect(as_stored_in_version[:time_zone].last).to(eq(serialized_value))
|
|
871
|
-
end
|
|
872
|
-
|
|
873
|
-
it "version.reify should convert attribute to original, unserialized value" do
|
|
874
|
-
unserialized_value = Person::TimeZoneSerializer.load(@attribute_value_before_change)
|
|
875
|
-
expect(@person.versions.last.reify.time_zone).to(eq(unserialized_value))
|
|
876
|
-
end
|
|
877
|
-
|
|
878
|
-
it "version.changeset should convert attribute to original, unserialized value" do
|
|
879
|
-
unserialized_value = Person::TimeZoneSerializer.load(@person.time_zone)
|
|
880
|
-
expect(@person.versions.last.changeset[:time_zone].last).to(eq(unserialized_value))
|
|
881
|
-
end
|
|
882
|
-
|
|
883
|
-
it "record.changes (before save) returns the original, unserialized values" do
|
|
884
|
-
expect(
|
|
885
|
-
@changes_before_save[:time_zone].map(&:class)
|
|
886
|
-
).to(eq([ActiveSupport::TimeZone, ActiveSupport::TimeZone]))
|
|
887
|
-
end
|
|
888
|
-
|
|
889
|
-
it "version.changeset should be the same as record.changes was before the save" do
|
|
890
|
-
expect(@person.versions.last.changeset).to(eq(@changes_before_save))
|
|
891
|
-
expect(
|
|
892
|
-
@person.versions.last.changeset[:time_zone].map(&:class)
|
|
893
|
-
).to(eq([ActiveSupport::TimeZone, ActiveSupport::TimeZone]))
|
|
894
|
-
end
|
|
895
|
-
end
|
|
896
|
-
end
|
|
897
|
-
end
|
|
898
|
-
|
|
899
|
-
context "A new model instance which uses a custom PaperTrail::Version class" do
|
|
900
|
-
before { @post = Post.new }
|
|
901
|
-
|
|
902
|
-
context "which is then saved" do
|
|
903
|
-
before { @post.save }
|
|
904
|
-
|
|
905
|
-
it "change the number of post versions" do
|
|
906
|
-
expect(PostVersion.count).to(eq(1))
|
|
907
|
-
end
|
|
908
|
-
|
|
909
|
-
it "not change the number of versions" do
|
|
910
|
-
expect(PaperTrail::Version.count).to(eq(0))
|
|
911
|
-
end
|
|
912
|
-
end
|
|
913
|
-
end
|
|
914
|
-
|
|
915
|
-
context "An existing model instance which uses a custom PaperTrail::Version class" do
|
|
916
|
-
before { @post = Post.create }
|
|
917
|
-
|
|
918
|
-
it "have one post version" do
|
|
919
|
-
expect(PostVersion.count).to(eq(1))
|
|
920
|
-
end
|
|
921
|
-
|
|
922
|
-
context "on the first version" do
|
|
923
|
-
before { @version = @post.versions.first }
|
|
924
|
-
|
|
925
|
-
it "have the correct index" do
|
|
926
|
-
expect(@version.index).to(eq(0))
|
|
927
|
-
end
|
|
928
|
-
end
|
|
929
|
-
|
|
930
|
-
it "have versions of the custom class" do
|
|
931
|
-
expect(@post.versions.first.class.name).to(eq("PostVersion"))
|
|
932
|
-
end
|
|
933
|
-
|
|
934
|
-
context "which is modified" do
|
|
935
|
-
before { @post.update_attributes(content: "Some new content") }
|
|
936
|
-
|
|
937
|
-
it "change the number of post versions" do
|
|
938
|
-
expect(PostVersion.count).to(eq(2))
|
|
939
|
-
end
|
|
940
|
-
|
|
941
|
-
it "not change the number of versions" do
|
|
942
|
-
expect(PaperTrail::Version.count).to(eq(0))
|
|
943
|
-
end
|
|
944
|
-
|
|
945
|
-
it "not have stored changes when object_changes column doesn't exist" do
|
|
946
|
-
expect(@post.versions.last.changeset).to(be_nil)
|
|
947
|
-
end
|
|
948
|
-
end
|
|
949
|
-
end
|
|
950
|
-
|
|
951
|
-
context "An overwritten default accessor" do
|
|
952
|
-
before do
|
|
953
|
-
@song = Song.create(length: 4)
|
|
954
|
-
@song.update_attributes(length: 5)
|
|
955
|
-
end
|
|
956
|
-
|
|
957
|
-
it "return \"overwritten\" value on live instance" do
|
|
958
|
-
expect(@song.length).to(eq(5))
|
|
959
|
-
end
|
|
960
|
-
|
|
961
|
-
it "return \"overwritten\" value on reified instance" do
|
|
962
|
-
expect(@song.versions.last.reify.length).to(eq(4))
|
|
963
|
-
end
|
|
964
|
-
|
|
965
|
-
context "Has a virtual attribute injected into the ActiveModel::Dirty changes" do
|
|
966
|
-
before do
|
|
967
|
-
@song.name = "Good Vibrations"
|
|
968
|
-
@song.save
|
|
969
|
-
@song.name = "Yellow Submarine"
|
|
970
|
-
end
|
|
971
|
-
|
|
972
|
-
it "return persist the changes on the live instance properly" do
|
|
973
|
-
expect(@song.name).to(eq("Yellow Submarine"))
|
|
974
|
-
end
|
|
975
|
-
|
|
976
|
-
it "return \"overwritten\" virtual attribute on the reified instance" do
|
|
977
|
-
expect(@song.versions.last.reify.name).to(eq("Good Vibrations"))
|
|
978
|
-
end
|
|
979
|
-
end
|
|
980
|
-
end
|
|
981
|
-
|
|
982
|
-
context "An unsaved record" do
|
|
983
|
-
before do
|
|
984
|
-
@widget = Widget.new
|
|
985
|
-
@widget.destroy
|
|
986
|
-
end
|
|
987
|
-
|
|
988
|
-
it "not have a version created on destroy" do
|
|
989
|
-
expect(@widget.versions.empty?).to(eq(true))
|
|
990
|
-
end
|
|
991
|
-
end
|
|
992
|
-
end
|