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
data/spec/models/widget_spec.rb
DELETED
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe Widget, type: :model do
|
|
4
|
-
describe "`be_versioned` matcher" do
|
|
5
|
-
it { is_expected.to be_versioned }
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
let(:widget) { Widget.create! name: "Bob", an_integer: 1 }
|
|
9
|
-
|
|
10
|
-
describe "`have_a_version_with` matcher", versioning: true do
|
|
11
|
-
before do
|
|
12
|
-
widget.update_attributes!(name: "Leonard", an_integer: 1)
|
|
13
|
-
widget.update_attributes!(name: "Tom")
|
|
14
|
-
widget.update_attributes!(name: "Bob")
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it "is possible to do assertions on version attributes" do
|
|
18
|
-
expect(widget).to have_a_version_with name: "Leonard", an_integer: 1
|
|
19
|
-
expect(widget).to have_a_version_with an_integer: 1
|
|
20
|
-
expect(widget).to have_a_version_with name: "Tom"
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
describe "`have_a_version_with_changes` matcher", versioning: true do
|
|
25
|
-
before do
|
|
26
|
-
widget.update_attributes!(name: "Leonard", an_integer: 2)
|
|
27
|
-
widget.update_attributes!(name: "Tom")
|
|
28
|
-
widget.update_attributes!(name: "Bob")
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it "is possible to do assertions on version changes" do
|
|
32
|
-
expect(widget).to have_a_version_with_changes name: "Leonard", an_integer: 2
|
|
33
|
-
expect(widget).to have_a_version_with_changes an_integer: 2
|
|
34
|
-
expect(widget).to have_a_version_with_changes name: "Tom"
|
|
35
|
-
expect(widget).to have_a_version_with_changes name: "Bob"
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
describe "versioning option" do
|
|
40
|
-
context "enabled", versioning: true do
|
|
41
|
-
it "enables versioning" do
|
|
42
|
-
expect(widget.versions.size).to eq(1)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
context "disabled (default)" do
|
|
47
|
-
it "does not enable versioning" do
|
|
48
|
-
expect(widget.versions.size).to eq(0)
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
describe "Callbacks", versioning: true do
|
|
54
|
-
describe "before_save" do
|
|
55
|
-
before { widget.update_attributes!(name: "Foobar") }
|
|
56
|
-
|
|
57
|
-
subject { widget.versions.last.reify }
|
|
58
|
-
|
|
59
|
-
it "resets value for timestamp attrs for update so that value gets updated properly" do
|
|
60
|
-
# Travel 1 second because MySQL lacks sub-second resolution
|
|
61
|
-
Timecop.travel(1) do
|
|
62
|
-
expect { subject.save! }.to change(subject, :updated_at)
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
describe "after_create" do
|
|
68
|
-
let(:widget) { Widget.create!(name: "Foobar", created_at: Time.now - 1.week) }
|
|
69
|
-
|
|
70
|
-
it "corresponding version uses the widget's `updated_at`" do
|
|
71
|
-
expect(widget.versions.last.created_at.to_i).to eq(widget.updated_at.to_i)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
describe "after_update" do
|
|
76
|
-
before { widget.update_attributes!(name: "Foobar", updated_at: Time.now + 1.week) }
|
|
77
|
-
|
|
78
|
-
subject { widget.versions.last.reify }
|
|
79
|
-
|
|
80
|
-
it { expect(subject.paper_trail).not_to be_live }
|
|
81
|
-
|
|
82
|
-
it "clears the `versions_association_name` virtual attribute" do
|
|
83
|
-
subject.save!
|
|
84
|
-
expect(subject.paper_trail).to be_live
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it "corresponding version uses the widget updated_at" do
|
|
88
|
-
expect(widget.versions.last.created_at.to_i).to eq(widget.updated_at.to_i)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
describe "after_destroy" do
|
|
93
|
-
it "creates a version for that event" do
|
|
94
|
-
expect { widget.destroy }.to change(widget.versions, :count).by(1)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
it "assigns the version into the `versions_association_name`" do
|
|
98
|
-
expect(widget.version).to be_nil
|
|
99
|
-
widget.destroy
|
|
100
|
-
expect(widget.version).not_to be_nil
|
|
101
|
-
expect(widget.version).to eq(widget.versions.last)
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
describe "after_rollback" do
|
|
106
|
-
let(:rolled_back_name) { "Big Moo" }
|
|
107
|
-
|
|
108
|
-
before do
|
|
109
|
-
begin
|
|
110
|
-
widget.transaction do
|
|
111
|
-
widget.update_attributes!(name: rolled_back_name)
|
|
112
|
-
widget.update_attributes!(name: Widget::EXCLUDED_NAME)
|
|
113
|
-
end
|
|
114
|
-
rescue ActiveRecord::RecordInvalid
|
|
115
|
-
widget.reload
|
|
116
|
-
widget.name = nil
|
|
117
|
-
widget.save
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
it "does not create an event for changes that did not happen" do
|
|
122
|
-
widget.versions.map(&:changeset).each do |changeset|
|
|
123
|
-
expect(changeset.fetch("name", [])).not_to include(rolled_back_name)
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
it "has not yet loaded the assocation" do
|
|
128
|
-
expect(widget.versions).not_to be_loaded
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
describe "Association", versioning: true do
|
|
134
|
-
describe "sort order" do
|
|
135
|
-
it "sorts by the timestamp order from the `VersionConcern`" do
|
|
136
|
-
expect(widget.versions.to_sql).to eq(
|
|
137
|
-
widget.versions.reorder(PaperTrail::Version.timestamp_sort_order).to_sql
|
|
138
|
-
)
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
if defined?(ActiveRecord::IdentityMap) && ActiveRecord::IdentityMap.respond_to?(:without)
|
|
144
|
-
describe "IdentityMap", versioning: true do
|
|
145
|
-
it "does not clobber the IdentityMap when reifying" do
|
|
146
|
-
widget.update_attributes name: "Henry", created_at: Time.now - 1.day
|
|
147
|
-
widget.update_attributes name: "Harry"
|
|
148
|
-
expect(ActiveRecord::IdentityMap).to receive(:without).once
|
|
149
|
-
widget.versions.last.reify
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
describe "#create", versioning: true do
|
|
155
|
-
it "creates a version record" do
|
|
156
|
-
wordget = Widget.create
|
|
157
|
-
assert_equal 1, wordget.versions.length
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
describe "#destroy", versioning: true do
|
|
162
|
-
it "creates a version record" do
|
|
163
|
-
widget = Widget.create
|
|
164
|
-
assert_equal 1, widget.versions.length
|
|
165
|
-
widget.destroy
|
|
166
|
-
versions_for_widget = PaperTrail::Version.with_item_keys("Widget", widget.id)
|
|
167
|
-
assert_equal 2, versions_for_widget.length
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
it "can have multiple destruction records" do
|
|
171
|
-
versions = lambda { |widget|
|
|
172
|
-
# Workaround for AR 3. When we drop AR 3 support, we can simply use
|
|
173
|
-
# the `widget.versions` association, instead of `with_item_keys`.
|
|
174
|
-
PaperTrail::Version.with_item_keys("Widget", widget.id)
|
|
175
|
-
}
|
|
176
|
-
widget = Widget.create
|
|
177
|
-
assert_equal 1, widget.versions.length
|
|
178
|
-
widget.destroy
|
|
179
|
-
assert_equal 2, versions.call(widget).length
|
|
180
|
-
widget = widget.version.reify
|
|
181
|
-
widget.save
|
|
182
|
-
assert_equal 3, versions.call(widget).length
|
|
183
|
-
widget.destroy
|
|
184
|
-
assert_equal 4, versions.call(widget).length
|
|
185
|
-
assert_equal 2, versions.call(widget).where(event: "destroy").length
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
describe "#paper_trail.originator", versioning: true do
|
|
190
|
-
describe "return value" do
|
|
191
|
-
let(:orig_name) { FFaker::Name.name }
|
|
192
|
-
let(:new_name) { FFaker::Name.name }
|
|
193
|
-
|
|
194
|
-
before do
|
|
195
|
-
PaperTrail.whodunnit = orig_name
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
it "returns the originator for the model at a given state" do
|
|
199
|
-
expect(widget.paper_trail).to be_live
|
|
200
|
-
expect(widget.paper_trail.originator).to eq(orig_name)
|
|
201
|
-
widget.paper_trail.whodunnit(new_name) { |w|
|
|
202
|
-
w.update_attributes(name: "Elizabeth")
|
|
203
|
-
}
|
|
204
|
-
expect(widget.paper_trail.originator).to eq(new_name)
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
it "returns the appropriate originator" do
|
|
208
|
-
widget.update_attributes(name: "Andy")
|
|
209
|
-
PaperTrail.whodunnit = new_name
|
|
210
|
-
widget.update_attributes(name: "Elizabeth")
|
|
211
|
-
reified_widget = widget.versions[1].reify
|
|
212
|
-
expect(reified_widget.paper_trail.originator).to eq(orig_name)
|
|
213
|
-
expect(reified_widget).not_to be_new_record
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
it "can create a new instance with options[:dup]" do
|
|
217
|
-
widget.update_attributes(name: "Andy")
|
|
218
|
-
PaperTrail.whodunnit = new_name
|
|
219
|
-
widget.update_attributes(name: "Elizabeth")
|
|
220
|
-
reified_widget = widget.versions[1].reify(dup: true)
|
|
221
|
-
expect(reified_widget.paper_trail.originator).to eq(orig_name)
|
|
222
|
-
expect(reified_widget).to be_new_record
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
describe "#version_at", versioning: true do
|
|
228
|
-
context "Timestamp argument is AFTER object has been destroyed" do
|
|
229
|
-
it "returns nil" do
|
|
230
|
-
widget.update_attribute(:name, "foobar")
|
|
231
|
-
widget.destroy
|
|
232
|
-
expect(widget.paper_trail.version_at(Time.now)).to be_nil
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
describe "#whodunnit", versioning: true do
|
|
238
|
-
context "no block given" do
|
|
239
|
-
it "raises an error" do
|
|
240
|
-
expect {
|
|
241
|
-
widget.paper_trail.whodunnit("Ben")
|
|
242
|
-
}.to raise_error(ArgumentError, "expected to receive a block")
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
context "block given" do
|
|
247
|
-
let(:orig_name) { FFaker::Name.name }
|
|
248
|
-
let(:new_name) { FFaker::Name.name }
|
|
249
|
-
|
|
250
|
-
before do
|
|
251
|
-
PaperTrail.whodunnit = orig_name
|
|
252
|
-
expect(widget.versions.last.whodunnit).to eq(orig_name) # persist `widget`
|
|
253
|
-
end
|
|
254
|
-
|
|
255
|
-
it "modifies value of `PaperTrail.whodunnit` while executing the block" do
|
|
256
|
-
widget.paper_trail.whodunnit(new_name) do
|
|
257
|
-
expect(PaperTrail.whodunnit).to eq(new_name)
|
|
258
|
-
widget.update_attributes(name: "Elizabeth")
|
|
259
|
-
end
|
|
260
|
-
expect(widget.versions.last.whodunnit).to eq(new_name)
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
it "reverts value of whodunnit to previous value after executing the block" do
|
|
264
|
-
widget.paper_trail.whodunnit(new_name) { |w|
|
|
265
|
-
w.update_attributes(name: "Elizabeth")
|
|
266
|
-
}
|
|
267
|
-
expect(PaperTrail.whodunnit).to eq(orig_name)
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
it "reverts to previous value, even if error within block" do
|
|
271
|
-
expect {
|
|
272
|
-
widget.paper_trail.whodunnit(new_name) { raise }
|
|
273
|
-
}.to raise_error(RuntimeError)
|
|
274
|
-
expect(PaperTrail.whodunnit).to eq(orig_name)
|
|
275
|
-
end
|
|
276
|
-
end
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
describe "#touch_with_version", versioning: true do
|
|
280
|
-
it "creates a version" do
|
|
281
|
-
count = widget.versions.size
|
|
282
|
-
# Travel 1 second because MySQL lacks sub-second resolution
|
|
283
|
-
Timecop.travel(1) do
|
|
284
|
-
widget.paper_trail.touch_with_version
|
|
285
|
-
end
|
|
286
|
-
expect(widget.versions.size).to eq(count + 1)
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
it "increments the `:updated_at` timestamp" do
|
|
290
|
-
time_was = widget.updated_at
|
|
291
|
-
# Travel 1 second because MySQL lacks sub-second resolution
|
|
292
|
-
Timecop.travel(1) do
|
|
293
|
-
widget.paper_trail.touch_with_version
|
|
294
|
-
end
|
|
295
|
-
expect(widget.updated_at).to be > time_was
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
describe "#update", versioning: true do
|
|
300
|
-
it "creates a version record" do
|
|
301
|
-
widget = Widget.create
|
|
302
|
-
assert_equal 1, widget.versions.length
|
|
303
|
-
widget.update_attributes(name: "Bugle")
|
|
304
|
-
assert_equal 2, widget.versions.length
|
|
305
|
-
end
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
describe ".paper_trail.enabled?" do
|
|
309
|
-
it "returns true" do
|
|
310
|
-
expect(Widget.paper_trail.enabled?).to eq(true)
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
describe ".disable" do
|
|
315
|
-
it "sets the `paper_trail.enabled?` to `false`" do
|
|
316
|
-
expect(Widget.paper_trail.enabled?).to eq(true)
|
|
317
|
-
Widget.paper_trail.disable
|
|
318
|
-
expect(Widget.paper_trail.enabled?).to eq(false)
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
after do
|
|
322
|
-
Widget.paper_trail.enable
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
describe ".enable" do
|
|
327
|
-
it "sets the `paper_trail.enabled?` to `true`" do
|
|
328
|
-
Widget.paper_trail.disable
|
|
329
|
-
expect(Widget.paper_trail.enabled?).to eq(false)
|
|
330
|
-
Widget.paper_trail.enable
|
|
331
|
-
expect(Widget.paper_trail.enabled?).to eq(true)
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
after do
|
|
335
|
-
Widget.paper_trail.enable
|
|
336
|
-
end
|
|
337
|
-
end
|
|
338
|
-
end
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe PaperTrail, type: :module, versioning: true do
|
|
4
|
-
describe "#config" do
|
|
5
|
-
it { is_expected.to respond_to(:config) }
|
|
6
|
-
|
|
7
|
-
it "allows for config values to be set" do
|
|
8
|
-
expect(subject.config.enabled).to eq(true)
|
|
9
|
-
subject.config.enabled = false
|
|
10
|
-
expect(subject.config.enabled).to eq(false)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it "accepts blocks and yield the config instance" do
|
|
14
|
-
expect(subject.config.enabled).to eq(true)
|
|
15
|
-
subject.config { |c| c.enabled = false }
|
|
16
|
-
expect(subject.config.enabled).to eq(false)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
describe "#configure" do
|
|
21
|
-
it { is_expected.to respond_to(:configure) }
|
|
22
|
-
|
|
23
|
-
it "is an alias for the `config` method" do
|
|
24
|
-
expect(subject.method(:configure)).to eq(subject.method(:config))
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe PaperTrail::VersionConcern do
|
|
4
|
-
before(:all) { require "support/alt_db_init" }
|
|
5
|
-
|
|
6
|
-
it "allows included class to have different connections" do
|
|
7
|
-
expect(Foo::Version.connection).not_to eq(Bar::Version.connection)
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
it "allows custom version class to share connection with superclass" do
|
|
11
|
-
expect(Foo::Version.connection).to eq(Foo::Document.connection)
|
|
12
|
-
expect(Bar::Version.connection).to eq(Bar::Document.connection)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
it "can be used with class_name option" do
|
|
16
|
-
expect(Foo::Document.version_class_name).to eq("Foo::Version")
|
|
17
|
-
expect(Bar::Document.version_class_name).to eq("Bar::Version")
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
describe "persistence", versioning: true do
|
|
21
|
-
it "stores versions in the correct corresponding db location" do
|
|
22
|
-
foo_doc = Foo::Document.create!(name: "foobar")
|
|
23
|
-
bar_doc = Bar::Document.create!(name: "raboof")
|
|
24
|
-
expect(foo_doc.versions.first).to be_instance_of(Foo::Version)
|
|
25
|
-
expect(bar_doc.versions.first).to be_instance_of(Bar::Version)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
module PaperTrail
|
|
4
|
-
::RSpec.describe VERSION do
|
|
5
|
-
describe "STRING" do
|
|
6
|
-
it "joins the numbers into a period separated string" do
|
|
7
|
-
expect(described_class::STRING).to eq(
|
|
8
|
-
[
|
|
9
|
-
described_class::MAJOR,
|
|
10
|
-
described_class::MINOR,
|
|
11
|
-
described_class::TINY,
|
|
12
|
-
described_class::PRE
|
|
13
|
-
].compact.join(".")
|
|
14
|
-
)
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
@@ -1,965 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe(::PaperTrail, versioning: true) do
|
|
4
|
-
CHAPTER_NAMES = [
|
|
5
|
-
"Down the Rabbit-Hole",
|
|
6
|
-
"The Pool of Tears",
|
|
7
|
-
"A Caucus-Race and a Long Tale",
|
|
8
|
-
"The Rabbit Sends in a Little Bill",
|
|
9
|
-
"Advice from a Caterpillar",
|
|
10
|
-
"Pig and Pepper",
|
|
11
|
-
"A Mad Tea-Party",
|
|
12
|
-
"The Queen's Croquet-Ground",
|
|
13
|
-
"The Mock Turtle's Story",
|
|
14
|
-
"The Lobster Quadrille",
|
|
15
|
-
"Who Stole the Tarts?",
|
|
16
|
-
"Alice's Evidence"
|
|
17
|
-
].freeze
|
|
18
|
-
|
|
19
|
-
after do
|
|
20
|
-
Timecop.return
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
context "a has_one association" do
|
|
24
|
-
before { @widget = Widget.create(name: "widget_0") }
|
|
25
|
-
|
|
26
|
-
context "before the associated was created" do
|
|
27
|
-
before do
|
|
28
|
-
@widget.update_attributes(name: "widget_1")
|
|
29
|
-
@wotsit = @widget.create_wotsit(name: "wotsit_0")
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
context "when reified" do
|
|
33
|
-
before { @widget0 = @widget.versions.last.reify(has_one: true) }
|
|
34
|
-
|
|
35
|
-
it "see the associated as it was at the time" do
|
|
36
|
-
expect(@widget0.wotsit).to be_nil
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it "not persist changes to the live association" do
|
|
40
|
-
expect(@widget.reload.wotsit).to(eq(@wotsit))
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
context "where the association is created between model versions" do
|
|
46
|
-
before do
|
|
47
|
-
@wotsit = @widget.create_wotsit(name: "wotsit_0")
|
|
48
|
-
Timecop.travel(1.second.since)
|
|
49
|
-
@widget.update_attributes(name: "widget_1")
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
context "when reified" do
|
|
53
|
-
before { @widget0 = @widget.versions.last.reify(has_one: true) }
|
|
54
|
-
|
|
55
|
-
it "see the associated as it was at the time" do
|
|
56
|
-
expect(@widget0.wotsit.name).to(eq("wotsit_0"))
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it "not persist changes to the live association" do
|
|
60
|
-
expect(@widget.reload.wotsit).to(eq(@wotsit))
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
context "and then the associated is updated between model versions" do
|
|
65
|
-
before do
|
|
66
|
-
@wotsit.update_attributes(name: "wotsit_1")
|
|
67
|
-
@wotsit.update_attributes(name: "wotsit_2")
|
|
68
|
-
Timecop.travel(1.second.since)
|
|
69
|
-
@widget.update_attributes(name: "widget_2")
|
|
70
|
-
@wotsit.update_attributes(name: "wotsit_3")
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
context "when reified" do
|
|
74
|
-
before { @widget1 = @widget.versions.last.reify(has_one: true) }
|
|
75
|
-
|
|
76
|
-
it "see the associated as it was at the time" do
|
|
77
|
-
expect(@widget1.wotsit.name).to(eq("wotsit_2"))
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
it "not persist changes to the live association" do
|
|
81
|
-
expect(@widget.reload.wotsit.name).to(eq("wotsit_3"))
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
context "when reified opting out of has_one reification" do
|
|
86
|
-
before { @widget1 = @widget.versions.last.reify(has_one: false) }
|
|
87
|
-
|
|
88
|
-
it "see the associated as it is live" do
|
|
89
|
-
expect(@widget1.wotsit.name).to(eq("wotsit_3"))
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
context "and then the associated is destroyed" do
|
|
95
|
-
before { @wotsit.destroy }
|
|
96
|
-
|
|
97
|
-
context "when reify" do
|
|
98
|
-
before { @widget1 = @widget.versions.last.reify(has_one: true) }
|
|
99
|
-
|
|
100
|
-
it "see the associated as it was at the time" do
|
|
101
|
-
expect(@widget1.wotsit).to(eq(@wotsit))
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
it "not persist changes to the live association" do
|
|
105
|
-
expect(@widget.reload.wotsit).to be_nil
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
context "and then the model is updated" do
|
|
110
|
-
before do
|
|
111
|
-
Timecop.travel(1.second.since)
|
|
112
|
-
@widget.update_attributes(name: "widget_3")
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
context "when reified" do
|
|
116
|
-
before { @widget2 = @widget.versions.last.reify(has_one: true) }
|
|
117
|
-
|
|
118
|
-
it "see the associated as it was at the time" do
|
|
119
|
-
expect(@widget2.wotsit).to be_nil
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
context "a has_many association" do
|
|
128
|
-
before { @customer = Customer.create(name: "customer_0") }
|
|
129
|
-
|
|
130
|
-
context "updated before the associated was created" do
|
|
131
|
-
before do
|
|
132
|
-
@customer.update_attributes!(name: "customer_1")
|
|
133
|
-
@customer.orders.create!(order_date: Date.today)
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
context "when reified" do
|
|
137
|
-
before { @customer0 = @customer.versions.last.reify(has_many: true) }
|
|
138
|
-
|
|
139
|
-
it "see the associated as it was at the time" do
|
|
140
|
-
expect(@customer0.orders).to(eq([]))
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
it "not persist changes to the live association" do
|
|
144
|
-
expect(@customer.orders.reload).not_to(eq([]))
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
context "when reified with option mark_for_destruction" do
|
|
149
|
-
it "mark the associated for destruction" do
|
|
150
|
-
@customer0 = @customer.versions.last.reify(has_many: true, mark_for_destruction: true)
|
|
151
|
-
expect(@customer0.orders.map(&:marked_for_destruction?)).to(eq([true]))
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
context "where the association is created between model versions" do
|
|
157
|
-
before do
|
|
158
|
-
@order = @customer.orders.create!(order_date: "order_date_0")
|
|
159
|
-
Timecop.travel(1.second.since)
|
|
160
|
-
@customer.update_attributes(name: "customer_1")
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
context "when reified" do
|
|
164
|
-
before { @customer0 = @customer.versions.last.reify(has_many: true) }
|
|
165
|
-
|
|
166
|
-
it "see the associated as it was at the time" do
|
|
167
|
-
expect(@customer0.orders.map(&:order_date)).to(eq(["order_date_0"]))
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
context "and then a nested has_many association is created" do
|
|
172
|
-
before { @order.line_items.create!(product: "product_0") }
|
|
173
|
-
|
|
174
|
-
context "when reified" do
|
|
175
|
-
before { @customer0 = @customer.versions.last.reify(has_many: true) }
|
|
176
|
-
|
|
177
|
-
it "see the live version of the nested association" do
|
|
178
|
-
expect(@customer0.orders.first.line_items.map(&:product)).to(eq(["product_0"]))
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
context "and then the associated is updated between model versions" do
|
|
184
|
-
before do
|
|
185
|
-
@order.update_attributes(order_date: "order_date_1")
|
|
186
|
-
@order.update_attributes(order_date: "order_date_2")
|
|
187
|
-
Timecop.travel(1.second.since)
|
|
188
|
-
@customer.update_attributes(name: "customer_2")
|
|
189
|
-
@order.update_attributes(order_date: "order_date_3")
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
context "when reified" do
|
|
193
|
-
before { @customer1 = @customer.versions.last.reify(has_many: true) }
|
|
194
|
-
|
|
195
|
-
it "see the associated as it was at the time" do
|
|
196
|
-
expect(@customer1.orders.map(&:order_date)).to(eq(["order_date_2"]))
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
it "not persist changes to the live association" do
|
|
200
|
-
expect(@customer.orders.reload.map(&:order_date)).to(eq(["order_date_3"]))
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
context "when reified opting out of has_many reification" do
|
|
205
|
-
before { @customer1 = @customer.versions.last.reify(has_many: false) }
|
|
206
|
-
|
|
207
|
-
it "see the associated as it is live" do
|
|
208
|
-
expect(@customer1.orders.map(&:order_date)).to(eq(["order_date_3"]))
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
context "and then the associated is destroyed" do
|
|
213
|
-
before { @order.destroy }
|
|
214
|
-
|
|
215
|
-
context "when reified" do
|
|
216
|
-
before { @customer1 = @customer.versions.last.reify(has_many: true) }
|
|
217
|
-
|
|
218
|
-
it "see the associated as it was at the time" do
|
|
219
|
-
expect(@customer1.orders.map(&:order_date)).to(eq(["order_date_2"]))
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
it "not persist changes to the live association" do
|
|
223
|
-
expect(@customer.orders.reload).to(eq([]))
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
context "and then the associated is destroyed" do
|
|
230
|
-
before { @order.destroy }
|
|
231
|
-
|
|
232
|
-
context "when reified" do
|
|
233
|
-
before { @customer1 = @customer.versions.last.reify(has_many: true) }
|
|
234
|
-
|
|
235
|
-
it "see the associated as it was at the time" do
|
|
236
|
-
expect(@customer1.orders.map(&:order_date)).to(eq([@order.order_date]))
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
it "not persist changes to the live association" do
|
|
240
|
-
expect(@customer.orders.reload).to(eq([]))
|
|
241
|
-
end
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
context "and then the associated is destroyed between model versions" do
|
|
246
|
-
before do
|
|
247
|
-
@order.destroy
|
|
248
|
-
Timecop.travel(1.second.since)
|
|
249
|
-
@customer.update_attributes(name: "customer_2")
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
context "when reified" do
|
|
253
|
-
before { @customer1 = @customer.versions.last.reify(has_many: true) }
|
|
254
|
-
|
|
255
|
-
it "see the associated as it was at the time" do
|
|
256
|
-
expect(@customer1.orders).to(eq([]))
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
context "and then another association is added" do
|
|
262
|
-
before { @customer.orders.create!(order_date: "order_date_1") }
|
|
263
|
-
|
|
264
|
-
context "when reified" do
|
|
265
|
-
before { @customer0 = @customer.versions.last.reify(has_many: true) }
|
|
266
|
-
|
|
267
|
-
it "see the associated as it was at the time" do
|
|
268
|
-
expect(@customer0.orders.map(&:order_date)).to(eq(["order_date_0"]))
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
it "not persist changes to the live association" do
|
|
272
|
-
expect(
|
|
273
|
-
@customer.orders.reload.map(&:order_date)
|
|
274
|
-
).to match_array(%w[order_date_0 order_date_1])
|
|
275
|
-
end
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
context "when reified with option mark_for_destruction" do
|
|
279
|
-
it "mark the newly associated for destruction" do
|
|
280
|
-
@customer0 = @customer.versions.last.reify(has_many: true, mark_for_destruction: true)
|
|
281
|
-
order = @customer0.orders.detect { |o| o.order_date == "order_date_1" }
|
|
282
|
-
expect(order).to be_marked_for_destruction
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
context "has_many through associations" do
|
|
290
|
-
context "Books, Authors, and Authorships" do
|
|
291
|
-
before { @book = Book.create(title: "book_0") }
|
|
292
|
-
|
|
293
|
-
context "updated before the associated was created" do
|
|
294
|
-
before do
|
|
295
|
-
@book.update_attributes!(title: "book_1")
|
|
296
|
-
@book.authors.create!(name: "author_0")
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
context "when reified" do
|
|
300
|
-
before { @book0 = @book.versions.last.reify(has_many: true) }
|
|
301
|
-
|
|
302
|
-
it "see the associated as it was at the time" do
|
|
303
|
-
expect(@book0.authors).to(eq([]))
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
it "not persist changes to the live association" do
|
|
307
|
-
expect(@book.authors.reload.map(&:name)).to(eq(["author_0"]))
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
context "when reified with option mark_for_destruction" do
|
|
312
|
-
before do
|
|
313
|
-
@book0 = @book.versions.last.reify(has_many: true, mark_for_destruction: true)
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
it "mark the associated for destruction" do
|
|
317
|
-
expect(@book0.authors.map(&:marked_for_destruction?)).to(eq([true]))
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
it "mark the associated-through for destruction" do
|
|
321
|
-
expect(@book0.authorships.map(&:marked_for_destruction?)).to(eq([true]))
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
context "updated before it is associated with an existing one" do
|
|
327
|
-
before do
|
|
328
|
-
person_existing = Person.create(name: "person_existing")
|
|
329
|
-
Timecop.travel(1.second.since)
|
|
330
|
-
@book.update_attributes!(title: "book_1")
|
|
331
|
-
(@book.authors << person_existing)
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
context "when reified" do
|
|
335
|
-
before { @book0 = @book.versions.last.reify(has_many: true) }
|
|
336
|
-
|
|
337
|
-
it "see the associated as it was at the time" do
|
|
338
|
-
expect(@book0.authors).to(eq([]))
|
|
339
|
-
end
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
context "when reified with option mark_for_destruction" do
|
|
343
|
-
before do
|
|
344
|
-
@book0 = @book.versions.last.reify(has_many: true, mark_for_destruction: true)
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
it "not mark the associated for destruction" do
|
|
348
|
-
expect(@book0.authors.map(&:marked_for_destruction?)).to(eq([false]))
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
it "mark the associated-through for destruction" do
|
|
352
|
-
expect(@book0.authorships.map(&:marked_for_destruction?)).to(eq([true]))
|
|
353
|
-
end
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
context "where the association is created between model versions" do
|
|
358
|
-
before do
|
|
359
|
-
@author = @book.authors.create!(name: "author_0")
|
|
360
|
-
@person_existing = Person.create(name: "person_existing")
|
|
361
|
-
Timecop.travel(1.second.since)
|
|
362
|
-
@book.update_attributes!(title: "book_1")
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
context "when reified" do
|
|
366
|
-
before { @book0 = @book.versions.last.reify(has_many: true) }
|
|
367
|
-
|
|
368
|
-
it "see the associated as it was at the time" do
|
|
369
|
-
expect(@book0.authors.map(&:name)).to(eq(["author_0"]))
|
|
370
|
-
end
|
|
371
|
-
end
|
|
372
|
-
|
|
373
|
-
context "and then the associated is updated between model versions" do
|
|
374
|
-
before do
|
|
375
|
-
@author.update_attributes(name: "author_1")
|
|
376
|
-
@author.update_attributes(name: "author_2")
|
|
377
|
-
Timecop.travel(1.second.since)
|
|
378
|
-
@book.update_attributes(title: "book_2")
|
|
379
|
-
@author.update_attributes(name: "author_3")
|
|
380
|
-
end
|
|
381
|
-
|
|
382
|
-
context "when reified" do
|
|
383
|
-
before { @book1 = @book.versions.last.reify(has_many: true) }
|
|
384
|
-
|
|
385
|
-
it "see the associated as it was at the time" do
|
|
386
|
-
expect(@book1.authors.map(&:name)).to(eq(["author_2"]))
|
|
387
|
-
end
|
|
388
|
-
|
|
389
|
-
it "not persist changes to the live association" do
|
|
390
|
-
expect(@book.authors.reload.map(&:name)).to(eq(["author_3"]))
|
|
391
|
-
end
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
context "when reified opting out of has_many reification" do
|
|
395
|
-
before { @book1 = @book.versions.last.reify(has_many: false) }
|
|
396
|
-
|
|
397
|
-
it "see the associated as it is live" do
|
|
398
|
-
expect(@book1.authors.map(&:name)).to(eq(["author_3"]))
|
|
399
|
-
end
|
|
400
|
-
end
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
context "and then the associated is destroyed" do
|
|
404
|
-
before { @author.destroy }
|
|
405
|
-
|
|
406
|
-
context "when reified" do
|
|
407
|
-
before { @book1 = @book.versions.last.reify(has_many: true) }
|
|
408
|
-
|
|
409
|
-
it "see the associated as it was at the time" do
|
|
410
|
-
expect(@book1.authors.map(&:name)).to(eq([@author.name]))
|
|
411
|
-
end
|
|
412
|
-
|
|
413
|
-
it "not persist changes to the live association" do
|
|
414
|
-
expect(@book.authors.reload).to(eq([]))
|
|
415
|
-
end
|
|
416
|
-
end
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
context "and then the associated is destroyed between model versions" do
|
|
420
|
-
before do
|
|
421
|
-
@author.destroy
|
|
422
|
-
Timecop.travel(1.second.since)
|
|
423
|
-
@book.update_attributes(title: "book_2")
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
context "when reified" do
|
|
427
|
-
before { @book1 = @book.versions.last.reify(has_many: true) }
|
|
428
|
-
|
|
429
|
-
it "see the associated as it was at the time" do
|
|
430
|
-
expect(@book1.authors).to(eq([]))
|
|
431
|
-
end
|
|
432
|
-
end
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
context "and then the associated is dissociated between model versions" do
|
|
436
|
-
before do
|
|
437
|
-
@book.authors = []
|
|
438
|
-
Timecop.travel(1.second.since)
|
|
439
|
-
@book.update_attributes(title: "book_2")
|
|
440
|
-
end
|
|
441
|
-
|
|
442
|
-
context "when reified" do
|
|
443
|
-
before { @book1 = @book.versions.last.reify(has_many: true) }
|
|
444
|
-
|
|
445
|
-
it "see the associated as it was at the time" do
|
|
446
|
-
expect(@book1.authors).to(eq([]))
|
|
447
|
-
end
|
|
448
|
-
end
|
|
449
|
-
end
|
|
450
|
-
|
|
451
|
-
context "and then another associated is created" do
|
|
452
|
-
before { @book.authors.create!(name: "author_1") }
|
|
453
|
-
|
|
454
|
-
context "when reified" do
|
|
455
|
-
before { @book0 = @book.versions.last.reify(has_many: true) }
|
|
456
|
-
|
|
457
|
-
it "only see the first associated" do
|
|
458
|
-
expect(@book0.authors.map(&:name)).to(eq(["author_0"]))
|
|
459
|
-
end
|
|
460
|
-
|
|
461
|
-
it "not persist changes to the live association" do
|
|
462
|
-
expect(@book.authors.reload.map(&:name)).to(eq(%w[author_0 author_1]))
|
|
463
|
-
end
|
|
464
|
-
end
|
|
465
|
-
|
|
466
|
-
context "when reified with option mark_for_destruction" do
|
|
467
|
-
before do
|
|
468
|
-
@book0 = @book.versions.last.reify(has_many: true, mark_for_destruction: true)
|
|
469
|
-
end
|
|
470
|
-
|
|
471
|
-
it "mark the newly associated for destruction" do
|
|
472
|
-
author = @book0.authors.detect { |a| a.name == "author_1" }
|
|
473
|
-
expect(author).to be_marked_for_destruction
|
|
474
|
-
end
|
|
475
|
-
|
|
476
|
-
it "mark the newly associated-through for destruction" do
|
|
477
|
-
authorship = @book0.authorships.detect { |as| as.author.name == "author_1" }
|
|
478
|
-
expect(authorship).to be_marked_for_destruction
|
|
479
|
-
end
|
|
480
|
-
end
|
|
481
|
-
end
|
|
482
|
-
|
|
483
|
-
context "and then an existing one is associated" do
|
|
484
|
-
before { (@book.authors << @person_existing) }
|
|
485
|
-
|
|
486
|
-
context "when reified" do
|
|
487
|
-
before { @book0 = @book.versions.last.reify(has_many: true) }
|
|
488
|
-
|
|
489
|
-
it "only see the first associated" do
|
|
490
|
-
expect(@book0.authors.map(&:name)).to(eq(["author_0"]))
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
it "not persist changes to the live association" do
|
|
494
|
-
expect(@book.authors.reload.map(&:name).sort).to(eq(%w[author_0 person_existing]))
|
|
495
|
-
end
|
|
496
|
-
end
|
|
497
|
-
|
|
498
|
-
context "when reified with option mark_for_destruction" do
|
|
499
|
-
before do
|
|
500
|
-
@book0 = @book.versions.last.reify(has_many: true, mark_for_destruction: true)
|
|
501
|
-
end
|
|
502
|
-
|
|
503
|
-
it "not mark the newly associated for destruction" do
|
|
504
|
-
author = @book0.authors.detect { |a| a.name == "person_existing" }
|
|
505
|
-
expect(author).not_to be_marked_for_destruction
|
|
506
|
-
end
|
|
507
|
-
|
|
508
|
-
it "mark the newly associated-through for destruction" do
|
|
509
|
-
authorship = @book0.authorships.detect { |as| as.author.name == "person_existing" }
|
|
510
|
-
expect(authorship).to be_marked_for_destruction
|
|
511
|
-
end
|
|
512
|
-
end
|
|
513
|
-
end
|
|
514
|
-
end
|
|
515
|
-
|
|
516
|
-
context "updated before the associated without paper_trail was created" do
|
|
517
|
-
before do
|
|
518
|
-
@book.update_attributes!(title: "book_1")
|
|
519
|
-
@book.editors.create!(name: "editor_0")
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
context "when reified" do
|
|
523
|
-
before { @book0 = @book.versions.last.reify(has_many: true) }
|
|
524
|
-
|
|
525
|
-
it "see the live association" do
|
|
526
|
-
expect(@book0.editors.map(&:name)).to(eq(["editor_0"]))
|
|
527
|
-
end
|
|
528
|
-
end
|
|
529
|
-
end
|
|
530
|
-
end
|
|
531
|
-
|
|
532
|
-
context "Chapters, Sections, Paragraphs, Quotations, and Citations" do
|
|
533
|
-
before { @chapter = Chapter.create(name: CHAPTER_NAMES[0]) }
|
|
534
|
-
|
|
535
|
-
context "before any associations are created" do
|
|
536
|
-
before { @chapter.update_attributes(name: CHAPTER_NAMES[1]) }
|
|
537
|
-
|
|
538
|
-
it "not reify any associations" do
|
|
539
|
-
chapter_v1 = @chapter.versions[1].reify(has_many: true)
|
|
540
|
-
expect(chapter_v1.name).to(eq(CHAPTER_NAMES[0]))
|
|
541
|
-
expect(chapter_v1.sections).to(eq([]))
|
|
542
|
-
expect(chapter_v1.paragraphs).to(eq([]))
|
|
543
|
-
end
|
|
544
|
-
end
|
|
545
|
-
|
|
546
|
-
context "after the first has_many through relationship is created" do
|
|
547
|
-
before do
|
|
548
|
-
expect(@chapter.versions.size).to(eq(1))
|
|
549
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[1])
|
|
550
|
-
expect(@chapter.versions.size).to(eq(2))
|
|
551
|
-
Timecop.travel(1.second.since)
|
|
552
|
-
@chapter.sections.create(name: "section 1")
|
|
553
|
-
Timecop.travel(1.second.since)
|
|
554
|
-
@chapter.sections.first.update_attributes(name: "section 2")
|
|
555
|
-
Timecop.travel(1.second.since)
|
|
556
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[2])
|
|
557
|
-
expect(@chapter.versions.size).to(eq(3))
|
|
558
|
-
Timecop.travel(1.second.since)
|
|
559
|
-
@chapter.sections.first.update_attributes(name: "section 3")
|
|
560
|
-
end
|
|
561
|
-
|
|
562
|
-
context "version 1" do
|
|
563
|
-
it "have no sections" do
|
|
564
|
-
chapter_v1 = @chapter.versions[1].reify(has_many: true)
|
|
565
|
-
expect(chapter_v1.sections).to(eq([]))
|
|
566
|
-
end
|
|
567
|
-
end
|
|
568
|
-
|
|
569
|
-
context "version 2" do
|
|
570
|
-
it "have one section" do
|
|
571
|
-
chapter_v2 = @chapter.versions[2].reify(has_many: true)
|
|
572
|
-
expect(chapter_v2.sections.size).to(eq(1))
|
|
573
|
-
expect(chapter_v2.sections.map(&:name)).to(eq(["section 2"]))
|
|
574
|
-
expect(chapter_v2.name).to(eq(CHAPTER_NAMES[1]))
|
|
575
|
-
end
|
|
576
|
-
end
|
|
577
|
-
|
|
578
|
-
context "version 2, before the section was destroyed" do
|
|
579
|
-
before do
|
|
580
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[2])
|
|
581
|
-
Timecop.travel(1.second.since)
|
|
582
|
-
@chapter.sections.destroy_all
|
|
583
|
-
Timecop.travel(1.second.since)
|
|
584
|
-
end
|
|
585
|
-
|
|
586
|
-
it "have the one section" do
|
|
587
|
-
chapter_v2 = @chapter.versions[2].reify(has_many: true)
|
|
588
|
-
expect(chapter_v2.sections.map(&:name)).to(eq(["section 2"]))
|
|
589
|
-
end
|
|
590
|
-
end
|
|
591
|
-
|
|
592
|
-
context "version 3, after the section was destroyed" do
|
|
593
|
-
before do
|
|
594
|
-
@chapter.sections.destroy_all
|
|
595
|
-
Timecop.travel(1.second.since)
|
|
596
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[3])
|
|
597
|
-
Timecop.travel(1.second.since)
|
|
598
|
-
end
|
|
599
|
-
|
|
600
|
-
it "have no sections" do
|
|
601
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
|
602
|
-
expect(chapter_v3.sections.size).to(eq(0))
|
|
603
|
-
end
|
|
604
|
-
end
|
|
605
|
-
|
|
606
|
-
context "after creating a paragraph" do
|
|
607
|
-
before do
|
|
608
|
-
expect(@chapter.versions.size).to(eq(3))
|
|
609
|
-
@section = @chapter.sections.first
|
|
610
|
-
Timecop.travel(1.second.since)
|
|
611
|
-
@paragraph = @section.paragraphs.create(name: "para1")
|
|
612
|
-
end
|
|
613
|
-
|
|
614
|
-
context "new chapter version" do
|
|
615
|
-
it "have one paragraph" do
|
|
616
|
-
initial_section_name = @section.name
|
|
617
|
-
initial_paragraph_name = @paragraph.name
|
|
618
|
-
Timecop.travel(1.second.since)
|
|
619
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[4])
|
|
620
|
-
expect(@chapter.versions.size).to(eq(4))
|
|
621
|
-
Timecop.travel(1.second.since)
|
|
622
|
-
@paragraph.update_attributes(name: "para3")
|
|
623
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
|
624
|
-
expect(chapter_v3.sections.map(&:name)).to(eq([initial_section_name]))
|
|
625
|
-
paragraphs = chapter_v3.sections.first.paragraphs
|
|
626
|
-
expect(paragraphs.size).to(eq(1))
|
|
627
|
-
expect(paragraphs.map(&:name)).to(eq([initial_paragraph_name]))
|
|
628
|
-
end
|
|
629
|
-
end
|
|
630
|
-
|
|
631
|
-
context "the version before a section is destroyed" do
|
|
632
|
-
it "have the section and paragraph" do
|
|
633
|
-
Timecop.travel(1.second.since)
|
|
634
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[3])
|
|
635
|
-
expect(@chapter.versions.size).to(eq(4))
|
|
636
|
-
Timecop.travel(1.second.since)
|
|
637
|
-
@section.destroy
|
|
638
|
-
expect(@chapter.versions.size).to(eq(4))
|
|
639
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
|
640
|
-
expect(chapter_v3.name).to(eq(CHAPTER_NAMES[2]))
|
|
641
|
-
expect(chapter_v3.sections).to(eq([@section]))
|
|
642
|
-
expect(chapter_v3.sections[0].paragraphs).to(eq([@paragraph]))
|
|
643
|
-
expect(chapter_v3.paragraphs).to(eq([@paragraph]))
|
|
644
|
-
end
|
|
645
|
-
end
|
|
646
|
-
|
|
647
|
-
context "the version after a section is destroyed" do
|
|
648
|
-
it "not have any sections or paragraphs" do
|
|
649
|
-
@section.destroy
|
|
650
|
-
Timecop.travel(1.second.since)
|
|
651
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[5])
|
|
652
|
-
expect(@chapter.versions.size).to(eq(4))
|
|
653
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
|
654
|
-
expect(chapter_v3.sections.size).to(eq(0))
|
|
655
|
-
expect(chapter_v3.paragraphs.size).to(eq(0))
|
|
656
|
-
end
|
|
657
|
-
end
|
|
658
|
-
|
|
659
|
-
context "the version before a paragraph is destroyed" do
|
|
660
|
-
it "have the one paragraph" do
|
|
661
|
-
initial_paragraph_name = @section.paragraphs.first.name
|
|
662
|
-
Timecop.travel(1.second.since)
|
|
663
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[5])
|
|
664
|
-
Timecop.travel(1.second.since)
|
|
665
|
-
@paragraph.destroy
|
|
666
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
|
667
|
-
paragraphs = chapter_v3.sections.first.paragraphs
|
|
668
|
-
expect(paragraphs.size).to(eq(1))
|
|
669
|
-
expect(paragraphs.first.name).to(eq(initial_paragraph_name))
|
|
670
|
-
end
|
|
671
|
-
end
|
|
672
|
-
|
|
673
|
-
context "the version after a paragraph is destroyed" do
|
|
674
|
-
it "have no paragraphs" do
|
|
675
|
-
@paragraph.destroy
|
|
676
|
-
Timecop.travel(1.second.since)
|
|
677
|
-
@chapter.update_attributes(name: CHAPTER_NAMES[5])
|
|
678
|
-
chapter_v3 = @chapter.versions[3].reify(has_many: true)
|
|
679
|
-
expect(chapter_v3.paragraphs.size).to(eq(0))
|
|
680
|
-
expect(chapter_v3.sections.first.paragraphs).to(eq([]))
|
|
681
|
-
end
|
|
682
|
-
end
|
|
683
|
-
end
|
|
684
|
-
end
|
|
685
|
-
|
|
686
|
-
context "a chapter with one paragraph and one citation" do
|
|
687
|
-
it "reify paragraphs and citations" do
|
|
688
|
-
chapter = Chapter.create(name: CHAPTER_NAMES[0])
|
|
689
|
-
section = Section.create(name: "Section One", chapter: chapter)
|
|
690
|
-
paragraph = Paragraph.create(name: "Paragraph One", section: section)
|
|
691
|
-
quotation = Quotation.create(chapter: chapter)
|
|
692
|
-
citation = Citation.create(quotation: quotation)
|
|
693
|
-
Timecop.travel(1.second.since)
|
|
694
|
-
chapter.update_attributes(name: CHAPTER_NAMES[1])
|
|
695
|
-
expect(chapter.versions.count).to(eq(2))
|
|
696
|
-
paragraph.destroy
|
|
697
|
-
citation.destroy
|
|
698
|
-
reified = chapter.versions[1].reify(has_many: true)
|
|
699
|
-
expect(reified.sections.first.paragraphs).to(eq([paragraph]))
|
|
700
|
-
expect(reified.quotations.first.citations).to(eq([citation]))
|
|
701
|
-
end
|
|
702
|
-
end
|
|
703
|
-
end
|
|
704
|
-
end
|
|
705
|
-
|
|
706
|
-
context "belongs_to associations" do
|
|
707
|
-
context "Wotsit and Widget" do
|
|
708
|
-
before { @widget = Widget.create(name: "widget_0") }
|
|
709
|
-
|
|
710
|
-
context "where the association is created between model versions" do
|
|
711
|
-
before do
|
|
712
|
-
@wotsit = Wotsit.create(name: "wotsit_0")
|
|
713
|
-
Timecop.travel(1.second.since)
|
|
714
|
-
@wotsit.update_attributes(widget_id: @widget.id, name: "wotsit_1")
|
|
715
|
-
end
|
|
716
|
-
|
|
717
|
-
context "when reified" do
|
|
718
|
-
before { @wotsit0 = @wotsit.versions.last.reify(belongs_to: true) }
|
|
719
|
-
|
|
720
|
-
it "see the associated as it was at the time" do
|
|
721
|
-
expect(@wotsit0.widget).to be_nil
|
|
722
|
-
end
|
|
723
|
-
|
|
724
|
-
it "not persist changes to the live association" do
|
|
725
|
-
expect(@wotsit.reload.widget).to(eq(@widget))
|
|
726
|
-
end
|
|
727
|
-
end
|
|
728
|
-
|
|
729
|
-
context "and then the associated is updated between model versions" do
|
|
730
|
-
before do
|
|
731
|
-
@widget.update_attributes(name: "widget_1")
|
|
732
|
-
@widget.update_attributes(name: "widget_2")
|
|
733
|
-
Timecop.travel(1.second.since)
|
|
734
|
-
@wotsit.update_attributes(name: "wotsit_2")
|
|
735
|
-
@widget.update_attributes(name: "widget_3")
|
|
736
|
-
end
|
|
737
|
-
|
|
738
|
-
context "when reified" do
|
|
739
|
-
before { @wotsit1 = @wotsit.versions.last.reify(belongs_to: true) }
|
|
740
|
-
|
|
741
|
-
it "see the associated as it was at the time" do
|
|
742
|
-
expect(@wotsit1.widget.name).to(eq("widget_2"))
|
|
743
|
-
end
|
|
744
|
-
|
|
745
|
-
it "not persist changes to the live association" do
|
|
746
|
-
expect(@wotsit.reload.widget.name).to(eq("widget_3"))
|
|
747
|
-
end
|
|
748
|
-
end
|
|
749
|
-
|
|
750
|
-
context "when reified opting out of belongs_to reification" do
|
|
751
|
-
before { @wotsit1 = @wotsit.versions.last.reify(belongs_to: false) }
|
|
752
|
-
|
|
753
|
-
it "see the associated as it is live" do
|
|
754
|
-
expect(@wotsit1.widget.name).to(eq("widget_3"))
|
|
755
|
-
end
|
|
756
|
-
end
|
|
757
|
-
end
|
|
758
|
-
|
|
759
|
-
context "and then the associated is destroyed" do
|
|
760
|
-
before do
|
|
761
|
-
@wotsit.update_attributes(name: "wotsit_2")
|
|
762
|
-
@widget.destroy
|
|
763
|
-
end
|
|
764
|
-
|
|
765
|
-
context "when reified with belongs_to: true" do
|
|
766
|
-
before { @wotsit2 = @wotsit.versions.last.reify(belongs_to: true) }
|
|
767
|
-
|
|
768
|
-
it "see the associated as it was at the time" do
|
|
769
|
-
expect(@wotsit2.widget).to(eq(@widget))
|
|
770
|
-
end
|
|
771
|
-
|
|
772
|
-
it "not persist changes to the live association" do
|
|
773
|
-
expect(@wotsit.reload.widget).to be_nil
|
|
774
|
-
end
|
|
775
|
-
|
|
776
|
-
it "be able to persist the reified record" do
|
|
777
|
-
expect { @wotsit2.save! }.not_to(raise_error)
|
|
778
|
-
end
|
|
779
|
-
end
|
|
780
|
-
|
|
781
|
-
context "when reified with belongs_to: false" do
|
|
782
|
-
before { @wotsit2 = @wotsit.versions.last.reify(belongs_to: false) }
|
|
783
|
-
|
|
784
|
-
it "save should not re-create the widget record" do
|
|
785
|
-
@wotsit2.save!
|
|
786
|
-
expect(::Widget.find_by(id: @widget.id)).to be_nil
|
|
787
|
-
end
|
|
788
|
-
end
|
|
789
|
-
|
|
790
|
-
context "and then the model is updated" do
|
|
791
|
-
before do
|
|
792
|
-
Timecop.travel(1.second.since)
|
|
793
|
-
@wotsit.update_attributes(name: "wotsit_3")
|
|
794
|
-
end
|
|
795
|
-
|
|
796
|
-
context "when reified" do
|
|
797
|
-
before { @wotsit2 = @wotsit.versions.last.reify(belongs_to: true) }
|
|
798
|
-
|
|
799
|
-
it "see the associated as it was the time" do
|
|
800
|
-
expect(@wotsit2.widget).to be_nil
|
|
801
|
-
end
|
|
802
|
-
end
|
|
803
|
-
end
|
|
804
|
-
end
|
|
805
|
-
end
|
|
806
|
-
|
|
807
|
-
context "where the association is changed between model versions" do
|
|
808
|
-
before do
|
|
809
|
-
@wotsit = @widget.create_wotsit(name: "wotsit_0")
|
|
810
|
-
Timecop.travel(1.second.since)
|
|
811
|
-
@new_widget = Widget.create(name: "new_widget")
|
|
812
|
-
@wotsit.update_attributes(widget_id: @new_widget.id, name: "wotsit_1")
|
|
813
|
-
end
|
|
814
|
-
|
|
815
|
-
context "when reified" do
|
|
816
|
-
before { @wotsit0 = @wotsit.versions.last.reify(belongs_to: true) }
|
|
817
|
-
|
|
818
|
-
it "see the association as it was at the time" do
|
|
819
|
-
expect(@wotsit0.widget.name).to(eq("widget_0"))
|
|
820
|
-
end
|
|
821
|
-
|
|
822
|
-
it "not persist changes to the live association" do
|
|
823
|
-
expect(@wotsit.reload.widget).to(eq(@new_widget))
|
|
824
|
-
end
|
|
825
|
-
end
|
|
826
|
-
|
|
827
|
-
context "when reified with option mark_for_destruction" do
|
|
828
|
-
before do
|
|
829
|
-
@wotsit0 = @wotsit.versions.last.reify(belongs_to: true, mark_for_destruction: true)
|
|
830
|
-
end
|
|
831
|
-
|
|
832
|
-
it "does not mark the new associated for destruction" do
|
|
833
|
-
expect(@new_widget.marked_for_destruction?).to(eq(false))
|
|
834
|
-
end
|
|
835
|
-
end
|
|
836
|
-
end
|
|
837
|
-
end
|
|
838
|
-
end
|
|
839
|
-
|
|
840
|
-
context "has_and_belongs_to_many associations" do
|
|
841
|
-
context "foo and bar" do
|
|
842
|
-
before do
|
|
843
|
-
@foo = FooHabtm.create(name: "foo")
|
|
844
|
-
Timecop.travel(1.second.since)
|
|
845
|
-
end
|
|
846
|
-
|
|
847
|
-
context "where the association is created between model versions" do
|
|
848
|
-
before do
|
|
849
|
-
@foo.update_attributes(name: "foo1", bar_habtms: [BarHabtm.create(name: "bar")])
|
|
850
|
-
end
|
|
851
|
-
|
|
852
|
-
context "when reified" do
|
|
853
|
-
before do
|
|
854
|
-
@reified = @foo.versions.last.reify(has_and_belongs_to_many: true)
|
|
855
|
-
end
|
|
856
|
-
|
|
857
|
-
it "see the associated as it was at the time" do
|
|
858
|
-
expect(@reified.bar_habtms.length).to(eq(0))
|
|
859
|
-
end
|
|
860
|
-
|
|
861
|
-
it "not persist changes to the live association" do
|
|
862
|
-
expect(@foo.reload.bar_habtms).not_to(eq(@reified.bar_habtms))
|
|
863
|
-
end
|
|
864
|
-
end
|
|
865
|
-
end
|
|
866
|
-
|
|
867
|
-
context "where the association is changed between model versions" do
|
|
868
|
-
before do
|
|
869
|
-
@foo.update_attributes(name: "foo2", bar_habtms: [BarHabtm.create(name: "bar2")])
|
|
870
|
-
Timecop.travel(1.second.since)
|
|
871
|
-
@foo.update_attributes(name: "foo3", bar_habtms: [BarHabtm.create(name: "bar3")])
|
|
872
|
-
end
|
|
873
|
-
|
|
874
|
-
context "when reified" do
|
|
875
|
-
before do
|
|
876
|
-
@reified = @foo.versions.last.reify(has_and_belongs_to_many: true)
|
|
877
|
-
end
|
|
878
|
-
|
|
879
|
-
it "see the association as it was at the time" do
|
|
880
|
-
expect(@reified.bar_habtms.first.name).to(eq("bar2"))
|
|
881
|
-
end
|
|
882
|
-
|
|
883
|
-
it "not persist changes to the live association" do
|
|
884
|
-
expect(@foo.reload.bar_habtms.first).not_to(eq(@reified.bar_habtms.first))
|
|
885
|
-
end
|
|
886
|
-
end
|
|
887
|
-
|
|
888
|
-
context "when reified with has_and_belongs_to_many: false" do
|
|
889
|
-
before { @reified = @foo.versions.last.reify }
|
|
890
|
-
|
|
891
|
-
it "see the association as it is now" do
|
|
892
|
-
expect(@reified.bar_habtms.first.name).to(eq("bar3"))
|
|
893
|
-
end
|
|
894
|
-
end
|
|
895
|
-
end
|
|
896
|
-
|
|
897
|
-
context "where the association is destroyed between model versions" do
|
|
898
|
-
before do
|
|
899
|
-
@foo.update_attributes(name: "foo2", bar_habtms: [BarHabtm.create(name: "bar2")])
|
|
900
|
-
Timecop.travel(1.second.since)
|
|
901
|
-
@foo.update_attributes(name: "foo3", bar_habtms: [])
|
|
902
|
-
end
|
|
903
|
-
|
|
904
|
-
context "when reified" do
|
|
905
|
-
before do
|
|
906
|
-
@reified = @foo.versions.last.reify(has_and_belongs_to_many: true)
|
|
907
|
-
end
|
|
908
|
-
|
|
909
|
-
it "see the association as it was at the time" do
|
|
910
|
-
expect(@reified.bar_habtms.first.name).to(eq("bar2"))
|
|
911
|
-
end
|
|
912
|
-
|
|
913
|
-
it "not persist changes to the live association" do
|
|
914
|
-
expect(@foo.reload.bar_habtms.first).not_to(eq(@reified.bar_habtms.first))
|
|
915
|
-
end
|
|
916
|
-
end
|
|
917
|
-
end
|
|
918
|
-
|
|
919
|
-
context "where the unassociated model changes" do
|
|
920
|
-
before do
|
|
921
|
-
@bar = BarHabtm.create(name: "bar2")
|
|
922
|
-
@foo.update_attributes(name: "foo2", bar_habtms: [@bar])
|
|
923
|
-
Timecop.travel(1.second.since)
|
|
924
|
-
@foo.update_attributes(name: "foo3", bar_habtms: [BarHabtm.create(name: "bar4")])
|
|
925
|
-
Timecop.travel(1.second.since)
|
|
926
|
-
@bar.update_attributes(name: "bar3")
|
|
927
|
-
end
|
|
928
|
-
|
|
929
|
-
context "when reified" do
|
|
930
|
-
before do
|
|
931
|
-
@reified = @foo.versions.last.reify(has_and_belongs_to_many: true)
|
|
932
|
-
end
|
|
933
|
-
|
|
934
|
-
it "see the association as it was at the time" do
|
|
935
|
-
expect(@reified.bar_habtms.first.name).to(eq("bar2"))
|
|
936
|
-
end
|
|
937
|
-
|
|
938
|
-
it "not persist changes to the live association" do
|
|
939
|
-
expect(@foo.reload.bar_habtms.first).not_to(eq(@reified.bar_habtms.first))
|
|
940
|
-
end
|
|
941
|
-
end
|
|
942
|
-
end
|
|
943
|
-
end
|
|
944
|
-
|
|
945
|
-
context "updated via nested attributes" do
|
|
946
|
-
before do
|
|
947
|
-
@foo = FooHabtm.create(name: "foo", bar_habtms_attributes: [{ name: "bar" }])
|
|
948
|
-
Timecop.travel(1.second.since)
|
|
949
|
-
@foo.update_attributes(
|
|
950
|
-
name: "foo2",
|
|
951
|
-
bar_habtms_attributes: [{ id: @foo.bar_habtms.first.id, name: "bar2" }]
|
|
952
|
-
)
|
|
953
|
-
@reified = @foo.versions.last.reify(has_and_belongs_to_many: true)
|
|
954
|
-
end
|
|
955
|
-
|
|
956
|
-
it "see the associated object as it was at the time" do
|
|
957
|
-
expect(@reified.bar_habtms.first.name).to(eq("bar"))
|
|
958
|
-
end
|
|
959
|
-
|
|
960
|
-
it "not persist changes to the live object" do
|
|
961
|
-
expect(@foo.reload.bar_habtms.first.name).not_to(eq(@reified.bar_habtms.first.name))
|
|
962
|
-
end
|
|
963
|
-
end
|
|
964
|
-
end
|
|
965
|
-
end
|