copyable 0.0.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 +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +264 -0
- data/Rakefile +7 -0
- data/copyable.gemspec +28 -0
- data/lib/copyable.rb +32 -0
- data/lib/copyable/config.rb +19 -0
- data/lib/copyable/copy_registry.rb +50 -0
- data/lib/copyable/copyable_extension.rb +118 -0
- data/lib/copyable/declarations/after_copy.rb +15 -0
- data/lib/copyable/declarations/associations.rb +116 -0
- data/lib/copyable/declarations/columns.rb +34 -0
- data/lib/copyable/declarations/declaration.rb +15 -0
- data/lib/copyable/declarations/declarations.rb +14 -0
- data/lib/copyable/declarations/disable_all_callbacks_and_observers_except_validate.rb +9 -0
- data/lib/copyable/declarations/main.rb +32 -0
- data/lib/copyable/exceptions.rb +10 -0
- data/lib/copyable/model_hooks.rb +40 -0
- data/lib/copyable/option_checker.rb +23 -0
- data/lib/copyable/railtie.rb +9 -0
- data/lib/copyable/saver.rb +19 -0
- data/lib/copyable/single_copy_enforcer.rb +68 -0
- data/lib/copyable/syntax_checking/association_checker.rb +41 -0
- data/lib/copyable/syntax_checking/column_checker.rb +43 -0
- data/lib/copyable/syntax_checking/completeness_checker.rb +27 -0
- data/lib/copyable/syntax_checking/declaration_checker.rb +26 -0
- data/lib/copyable/syntax_checking/declaration_stubber.rb +18 -0
- data/lib/copyable/syntax_checking/syntax_checker.rb +15 -0
- data/lib/copyable/version.rb +3 -0
- data/lib/tasks/copyable.rake +55 -0
- data/spec/config_spec.rb +132 -0
- data/spec/copy_registry_spec.rb +55 -0
- data/spec/copyable_after_copy_spec.rb +28 -0
- data/spec/copyable_associations_spec.rb +366 -0
- data/spec/copyable_columns_spec.rb +116 -0
- data/spec/copyable_spec.rb +7 -0
- data/spec/create_copy_spec.rb +136 -0
- data/spec/deep_structure_copy_spec.rb +169 -0
- data/spec/helper/copyable_spec_helper.rb +15 -0
- data/spec/helper/test_models.rb +136 -0
- data/spec/helper/test_tables.rb +135 -0
- data/spec/model_hooks_spec.rb +66 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/stress_test_spec.rb +261 -0
- data/spec/syntax_checking/association_checker_spec.rb +80 -0
- data/spec/syntax_checking/column_checker_spec.rb +49 -0
- data/spec/syntax_checking/declaration_checker_spec.rb +58 -0
- data/spec/syntax_checking_spec.rb +258 -0
- data/spec/transaction_spec.rb +78 -0
- metadata +200 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative 'helper/copyable_spec_helper'
|
2
|
+
|
3
|
+
describe Copyable::CopyRegistry do
|
4
|
+
before(:all) do
|
5
|
+
DummyModelPerson = Struct.new(:id, :name)
|
6
|
+
DummyModelPlace = Struct.new(:id, :name)
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
Copyable::CopyRegistry.clear
|
11
|
+
@bob = DummyModelPerson.new(10, "Bob")
|
12
|
+
@new_bob = DummyModelPerson.new(11, "Copy of Bob")
|
13
|
+
@fred = DummyModelPerson.new(15, "Fred")
|
14
|
+
@new_fred = DummyModelPerson.new(16, "Copy of Fred")
|
15
|
+
@winnipeg = DummyModelPlace.new(89, "Winnipeg")
|
16
|
+
@new_winnipeg = DummyModelPlace.new(90, "Copy of Winnipeg")
|
17
|
+
@yellowknife = DummyModelPlace.new(10, "Yellowknife")
|
18
|
+
@new_yellowknife = DummyModelPlace.new(11, "Copy of Yellowknife")
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should know whether a model has already been copied' do
|
22
|
+
registry = Copyable::CopyRegistry
|
23
|
+
registry.register(@bob, @new_bob)
|
24
|
+
registry.register(@fred, @new_fred)
|
25
|
+
registry.register(@yellowknife, @new_yellowknife)
|
26
|
+
# using record option
|
27
|
+
expect(registry.already_copied?(record: @bob)).to be_truthy
|
28
|
+
expect(registry.already_copied?(record: @fred)).to be_truthy
|
29
|
+
expect(registry.already_copied?(record: @winnipeg)).to be_falsey
|
30
|
+
expect(registry.already_copied?(record: @yellowknife)).to be_truthy
|
31
|
+
# using id and class options
|
32
|
+
expect(registry.already_copied?(id: 10, class: DummyModelPerson)).to be_truthy
|
33
|
+
expect(registry.already_copied?(id: 15, class: DummyModelPerson)).to be_truthy
|
34
|
+
expect(registry.already_copied?(id: 89, class: DummyModelPlace)).to be_falsey
|
35
|
+
expect(registry.already_copied?(id: 10, class: DummyModelPlace)).to be_truthy
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should provide the copy of a model that has already been copied' do
|
39
|
+
registry = Copyable::CopyRegistry
|
40
|
+
registry.register(@bob, @new_bob)
|
41
|
+
registry.register(@fred, @new_fred)
|
42
|
+
registry.register(@winnipeg, @new_winnipeg)
|
43
|
+
registry.register(@yellowknife, @new_yellowknife)
|
44
|
+
# using record option
|
45
|
+
expect(registry.fetch_copy(record: @bob)).to eq(@new_bob)
|
46
|
+
expect(registry.fetch_copy(record: @fred)).to eq(@new_fred)
|
47
|
+
expect(registry.fetch_copy(record: @winnipeg)).to eq(@new_winnipeg)
|
48
|
+
expect(registry.fetch_copy(record: @yellowknife)).to eq(@new_yellowknife)
|
49
|
+
# using id and class options
|
50
|
+
expect(registry.fetch_copy(id: 10, class: DummyModelPerson)).to eq(@new_bob)
|
51
|
+
expect(registry.fetch_copy(id: 15, class: DummyModelPerson)).to eq(@new_fred)
|
52
|
+
expect(registry.fetch_copy(id: 89, class: DummyModelPlace)).to eq(@new_winnipeg)
|
53
|
+
expect(registry.fetch_copy(id: 10, class: DummyModelPlace)).to eq(@new_yellowknife)
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'helper/copyable_spec_helper'
|
2
|
+
|
3
|
+
describe 'copyable:after_copy' do
|
4
|
+
before(:each) do
|
5
|
+
undefine_copyable_in CopyableCoin
|
6
|
+
class CopyableCoin < ActiveRecord::Base
|
7
|
+
copyable do
|
8
|
+
disable_all_callbacks_and_observers_except_validate
|
9
|
+
columns({
|
10
|
+
kind: lambda { |orig| "Copy of #{orig.kind}" },
|
11
|
+
year: :copy,
|
12
|
+
})
|
13
|
+
associations({
|
14
|
+
})
|
15
|
+
after_copy do |original_model, new_model|
|
16
|
+
raise "#{original_model.kind} #{new_model.kind}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should execute the after_copy block after copying' do
|
23
|
+
coin = CopyableCoin.create!(kind: 'nickel', year: 1883)
|
24
|
+
expect {
|
25
|
+
coin.create_copy!
|
26
|
+
}.to raise_error(RuntimeError, "nickel Copy of nickel")
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,366 @@
|
|
1
|
+
require_relative 'helper/copyable_spec_helper'
|
2
|
+
|
3
|
+
describe 'copyable:associations' do
|
4
|
+
|
5
|
+
context 'copying a has many relationship' do
|
6
|
+
before(:each) do
|
7
|
+
undefine_copyable_in CopyablePetSitter
|
8
|
+
class CopyablePetSitter < ActiveRecord::Base
|
9
|
+
copyable do
|
10
|
+
disable_all_callbacks_and_observers_except_validate
|
11
|
+
columns({
|
12
|
+
name: :copy,
|
13
|
+
})
|
14
|
+
associations({
|
15
|
+
copyable_pet_sitting_patronages: :copy,
|
16
|
+
})
|
17
|
+
end
|
18
|
+
end
|
19
|
+
undefine_copyable_in CopyablePetSittingPatronage
|
20
|
+
class CopyablePetSittingPatronage < ActiveRecord::Base
|
21
|
+
copyable do
|
22
|
+
disable_all_callbacks_and_observers_except_validate
|
23
|
+
columns({
|
24
|
+
copyable_pet_id: :copy,
|
25
|
+
copyable_pet_sitter_id: :copy,
|
26
|
+
})
|
27
|
+
associations({
|
28
|
+
})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
it 'should produce copies of the associated records' do
|
33
|
+
pet1 = CopyablePet.create!(name: 'Pet1', kind: 'cat', birth_year: 2010)
|
34
|
+
pet2 = CopyablePet.create!(name: 'Pet2', kind: 'cat', birth_year: 2011)
|
35
|
+
pet3 = CopyablePet.create!(name: 'Pet3', kind: 'cat', birth_year: 2012)
|
36
|
+
sitter1 = CopyablePetSitter.create!(name: 'Sitter1')
|
37
|
+
sitter2 = CopyablePetSitter.create!(name: 'Sitter2')
|
38
|
+
sitter3 = CopyablePetSitter.create!(name: 'Sitter3')
|
39
|
+
sitter4 = CopyablePetSitter.create!(name: 'Sitter4')
|
40
|
+
patronage1 = CopyablePetSittingPatronage.create!(
|
41
|
+
copyable_pet_id: pet1.id,
|
42
|
+
copyable_pet_sitter_id: sitter2.id)
|
43
|
+
patronage2 = CopyablePetSittingPatronage.create!(
|
44
|
+
copyable_pet_id: pet2.id,
|
45
|
+
copyable_pet_sitter_id: sitter2.id)
|
46
|
+
patronage3 = CopyablePetSittingPatronage.create!(
|
47
|
+
copyable_pet_id: pet3.id,
|
48
|
+
copyable_pet_sitter_id: sitter4.id)
|
49
|
+
sitter2.reload
|
50
|
+
expect(sitter2.copyable_pet_sitting_patronages.size).to eq(2)
|
51
|
+
copied_sitter = sitter2.create_copy!
|
52
|
+
expect(copied_sitter.copyable_pet_sitting_patronages.size).to eq(2)
|
53
|
+
expect(copied_sitter.copyable_pets.map(&:name)).to match_array(['Pet1', 'Pet2'])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'do not copy' do
|
58
|
+
before(:each) do
|
59
|
+
undefine_copyable_in CopyablePetSitter
|
60
|
+
class CopyablePetSitter < ActiveRecord::Base
|
61
|
+
copyable do
|
62
|
+
disable_all_callbacks_and_observers_except_validate
|
63
|
+
columns({
|
64
|
+
name: :copy,
|
65
|
+
})
|
66
|
+
associations({
|
67
|
+
copyable_pet_sitting_patronages: :do_not_copy,
|
68
|
+
})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
undefine_copyable_in CopyablePetSittingPatronage
|
72
|
+
class CopyablePetSittingPatronage < ActiveRecord::Base
|
73
|
+
copyable do
|
74
|
+
disable_all_callbacks_and_observers_except_validate
|
75
|
+
columns({
|
76
|
+
copyable_pet_id: :copy,
|
77
|
+
copyable_pet_sitter_id: :copy,
|
78
|
+
})
|
79
|
+
associations({
|
80
|
+
})
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
it 'should not produce copies of the associated records' do
|
85
|
+
pet1 = CopyablePet.create!(name: 'Pet1', kind: 'cat', birth_year: 2010)
|
86
|
+
pet2 = CopyablePet.create!(name: 'Pet2', kind: 'cat', birth_year: 2011)
|
87
|
+
pet3 = CopyablePet.create!(name: 'Pet3', kind: 'cat', birth_year: 2012)
|
88
|
+
sitter1 = CopyablePetSitter.create!(name: 'Sitter1')
|
89
|
+
sitter2 = CopyablePetSitter.create!(name: 'Sitter2')
|
90
|
+
sitter3 = CopyablePetSitter.create!(name: 'Sitter3')
|
91
|
+
sitter4 = CopyablePetSitter.create!(name: 'Sitter4')
|
92
|
+
patronage1 = CopyablePetSittingPatronage.create!(
|
93
|
+
copyable_pet_id: pet1.id,
|
94
|
+
copyable_pet_sitter_id: sitter2.id)
|
95
|
+
patronage2 = CopyablePetSittingPatronage.create!(
|
96
|
+
copyable_pet_id: pet2.id,
|
97
|
+
copyable_pet_sitter_id: sitter2.id)
|
98
|
+
patronage3 = CopyablePetSittingPatronage.create!(
|
99
|
+
copyable_pet_id: pet3.id,
|
100
|
+
copyable_pet_sitter_id: sitter4.id)
|
101
|
+
sitter2.reload
|
102
|
+
expect(sitter2.copyable_pet_sitting_patronages.size).to eq(2)
|
103
|
+
expect(CopyablePetSittingPatronage.count).to eq(3)
|
104
|
+
copied_sitter = sitter2.create_copy!
|
105
|
+
expect(copied_sitter.copyable_pet_sitting_patronages.size).to eq(0)
|
106
|
+
expect(CopyablePetSittingPatronage.count).to eq(3)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'copying a has one relationship' do
|
111
|
+
before(:each) do
|
112
|
+
undefine_copyable_in CopyablePetProfile
|
113
|
+
class CopyablePetProfile < ActiveRecord::Base
|
114
|
+
copyable do
|
115
|
+
disable_all_callbacks_and_observers_except_validate
|
116
|
+
columns({
|
117
|
+
description: :copy,
|
118
|
+
nickname: :copy,
|
119
|
+
copyable_pet_id: lambda { |orig| 177777 }, # random bogus CopyablePet id since we don't need a real CopyablePet record for this test
|
120
|
+
})
|
121
|
+
associations({
|
122
|
+
copyable_address: :copy,
|
123
|
+
})
|
124
|
+
end
|
125
|
+
end
|
126
|
+
undefine_copyable_in CopyableAddress
|
127
|
+
class CopyableAddress < ActiveRecord::Base
|
128
|
+
copyable do
|
129
|
+
disable_all_callbacks_and_observers_except_validate
|
130
|
+
columns({
|
131
|
+
address1: :copy,
|
132
|
+
address2: :copy,
|
133
|
+
city: :copy,
|
134
|
+
state: :copy,
|
135
|
+
copyable_pet_profile_id: :copy,
|
136
|
+
})
|
137
|
+
associations({
|
138
|
+
})
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should produce a copy of the associated record' do
|
144
|
+
profile1 = CopyablePetProfile.create!(description: 'Prof1',
|
145
|
+
copyable_pet_id: 177777)
|
146
|
+
profile2 = CopyablePetProfile.create!(description: 'Prof2',
|
147
|
+
copyable_pet_id: 188888)
|
148
|
+
profile3 = CopyablePetProfile.create!(description: 'Prof3',
|
149
|
+
copyable_pet_id: 199999)
|
150
|
+
address1 = CopyableAddress.create!(address1: 'Add1',
|
151
|
+
city: 'Cambridge',
|
152
|
+
state: 'MA',
|
153
|
+
copyable_pet_profile_id: profile1.id)
|
154
|
+
address2 = CopyableAddress.create!(address1: 'Add2',
|
155
|
+
city: 'Boston',
|
156
|
+
state: 'MA',
|
157
|
+
copyable_pet_profile_id: profile2.id)
|
158
|
+
address3 = CopyableAddress.create!(address1: 'Add3',
|
159
|
+
city: 'Somerville',
|
160
|
+
state: 'MA',
|
161
|
+
copyable_pet_profile_id: profile3.id)
|
162
|
+
expect(CopyablePetProfile.count).to eq(3)
|
163
|
+
expect(CopyableAddress.count).to eq(3)
|
164
|
+
copied_profile = profile1.create_copy!
|
165
|
+
expect(CopyablePetProfile.count).to eq(4)
|
166
|
+
expect(CopyableAddress.count).to eq(4)
|
167
|
+
expect(copied_profile.copyable_address.address1).to eq('Add1')
|
168
|
+
expect(copied_profile.copyable_address.city).to eq('Cambridge')
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should not copy the associated record if it is nil' do
|
172
|
+
profile1 = CopyablePetProfile.create!(description: 'Prof1',
|
173
|
+
copyable_pet_id: 56565656) # bogus id
|
174
|
+
expect(CopyablePetProfile.count).to eq(1)
|
175
|
+
expect(CopyableAddress.count).to eq(0)
|
176
|
+
copied_profile = profile1.create_copy!
|
177
|
+
expect(CopyablePetProfile.count).to eq(2)
|
178
|
+
expect(CopyableAddress.count).to eq(0)
|
179
|
+
expect(copied_profile.copyable_address).to be_nil
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'copying a has and belongs to many relationship' do
|
184
|
+
before(:each) do
|
185
|
+
undefine_copyable_in CopyablePetFood
|
186
|
+
class CopyablePetFood < ActiveRecord::Base
|
187
|
+
copyable do
|
188
|
+
disable_all_callbacks_and_observers_except_validate
|
189
|
+
columns({
|
190
|
+
name: :copy,
|
191
|
+
})
|
192
|
+
associations({
|
193
|
+
copyable_pets: :copy_only_habtm_join_records,
|
194
|
+
})
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
it 'should produce a copy of the associations but not the records' do
|
199
|
+
pet1 = CopyablePet.create!(name: 'Pet1', kind: 'cat', birth_year: 2010)
|
200
|
+
pet2 = CopyablePet.create!(name: 'Pet2', kind: 'cat', birth_year: 2011)
|
201
|
+
pet3 = CopyablePet.create!(name: 'Pet3', kind: 'cat', birth_year: 2012)
|
202
|
+
food1 = CopyablePetFood.create!(name: 'Food1')
|
203
|
+
food2 = CopyablePetFood.create!(name: 'Food2')
|
204
|
+
food3 = CopyablePetFood.create!(name: 'Food3')
|
205
|
+
food4 = CopyablePetFood.create!(name: 'Food4')
|
206
|
+
food1.copyable_pets << pet1
|
207
|
+
food1.copyable_pets << pet2
|
208
|
+
food3.copyable_pets << pet3
|
209
|
+
copied_food1 = food1.create_copy!
|
210
|
+
copied_food2 = food2.create_copy!
|
211
|
+
copied_food3 = food3.create_copy!
|
212
|
+
expect(copied_food1.copyable_pets.map(&:name)).to match_array(['Pet1', 'Pet2'])
|
213
|
+
expect(copied_food2.copyable_pets.map(&:name)).to match_array([])
|
214
|
+
expect(copied_food3.copyable_pets.map(&:name)).to match_array(['Pet3'])
|
215
|
+
expect(pet1.copyable_pet_foods.size).to eq(2)
|
216
|
+
expect(CopyablePet.count).to eq(3)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context 'copying a polymorphic has many' do
|
221
|
+
before(:each) do
|
222
|
+
undefine_copyable_in CopyableProduct
|
223
|
+
class CopyableProduct < ActiveRecord::Base
|
224
|
+
copyable do
|
225
|
+
disable_all_callbacks_and_observers_except_validate
|
226
|
+
columns({
|
227
|
+
name: :copy,
|
228
|
+
})
|
229
|
+
associations({
|
230
|
+
copyable_pictures: :copy,
|
231
|
+
})
|
232
|
+
end
|
233
|
+
end
|
234
|
+
undefine_copyable_in CopyablePicture
|
235
|
+
class CopyablePicture < ActiveRecord::Base
|
236
|
+
copyable do
|
237
|
+
disable_all_callbacks_and_observers_except_validate
|
238
|
+
columns({
|
239
|
+
name: :copy,
|
240
|
+
imageable_id: :copy,
|
241
|
+
imageable_type: :copy,
|
242
|
+
picture_album_id: :copy,
|
243
|
+
})
|
244
|
+
associations({
|
245
|
+
})
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
it 'should produce a copy of the associations' do
|
250
|
+
product1 = CopyableProduct.create!(name: 'camera')
|
251
|
+
picture1 = CopyablePicture.create!(name: 'photo1')
|
252
|
+
picture2 = CopyablePicture.create!(name: 'photo2')
|
253
|
+
product1.copyable_pictures << picture1
|
254
|
+
product1.copyable_pictures << picture2
|
255
|
+
expect(CopyableProduct.count).to eq(1)
|
256
|
+
expect(CopyablePicture.count).to eq(2)
|
257
|
+
copied_product = product1.create_copy!
|
258
|
+
expect(CopyableProduct.count).to eq(2)
|
259
|
+
expect(CopyablePicture.count).to eq(4)
|
260
|
+
expect(copied_product.copyable_pictures.size).to eq(2)
|
261
|
+
expect(copied_product.copyable_pictures.map(&:id)).not_to match_array(product1.copyable_pictures.map(&:id))
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'with a custom foreign key' do
|
266
|
+
before(:each) do
|
267
|
+
undefine_copyable_in CopyablePicture
|
268
|
+
class CopyablePicture < ActiveRecord::Base
|
269
|
+
copyable do
|
270
|
+
disable_all_callbacks_and_observers_except_validate
|
271
|
+
columns({
|
272
|
+
name: :copy,
|
273
|
+
imageable_id: :copy,
|
274
|
+
imageable_type: :copy,
|
275
|
+
picture_album_id: :copy,
|
276
|
+
})
|
277
|
+
associations({
|
278
|
+
})
|
279
|
+
end
|
280
|
+
end
|
281
|
+
undefine_copyable_in CopyableAlbum
|
282
|
+
class CopyableAlbum < ActiveRecord::Base
|
283
|
+
copyable do
|
284
|
+
disable_all_callbacks_and_observers_except_validate
|
285
|
+
columns({
|
286
|
+
name: :copy,
|
287
|
+
})
|
288
|
+
associations({
|
289
|
+
copyable_pictures: :copy,
|
290
|
+
})
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'should produce copies of the associated records without an error' do
|
296
|
+
album = CopyableAlbum.create!(name: 'an album')
|
297
|
+
picture1 = CopyablePicture.create!(name: 'photo1')
|
298
|
+
picture2 = CopyablePicture.create!(name: 'photo2', copyable_album: album)
|
299
|
+
picture3 = CopyablePicture.create!(name: 'photo3', copyable_album: album)
|
300
|
+
expect(CopyableAlbum.count).to eq(1)
|
301
|
+
expect(CopyablePicture.count).to eq(3)
|
302
|
+
copied_album = album.create_copy!
|
303
|
+
expect(CopyableAlbum.count).to eq(2)
|
304
|
+
expect(CopyablePicture.count).to eq(5)
|
305
|
+
expect(copied_album.copyable_pictures.map(&:name)).to match_array(['photo2', 'photo3'])
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'should update polymorphic belongs_to associations correctly' do
|
309
|
+
# This tests how the update_other_belongs_to_associations method handles
|
310
|
+
# polymorphic assocations. Even though the steps of this example may be
|
311
|
+
# similar (or exactly the same) as another example, the behavior that this
|
312
|
+
# example describes is different and is a significant part of the
|
313
|
+
# correctness of the software.
|
314
|
+
album = CopyableAlbum.create!(name: 'an album')
|
315
|
+
picture1 = CopyablePicture.create!(name: 'photo1')
|
316
|
+
picture2 = CopyablePicture.create!(name: 'photo2', copyable_album: album)
|
317
|
+
picture3 = CopyablePicture.create!(name: 'photo3', copyable_album: album)
|
318
|
+
expect(CopyableAlbum.count).to eq(1)
|
319
|
+
expect(CopyablePicture.count).to eq(3)
|
320
|
+
copied_album = album.create_copy!
|
321
|
+
expect(CopyableAlbum.count).to eq(2)
|
322
|
+
expect(CopyablePicture.count).to eq(5)
|
323
|
+
expect(copied_album.copyable_pictures.map(&:name)).to match_array(['photo2', 'photo3'])
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context 'copying a has many relationship with a missing copyable declaration' do
|
328
|
+
before(:each) do
|
329
|
+
undefine_copyable_in CopyablePetSitter
|
330
|
+
class CopyablePetSitter < ActiveRecord::Base
|
331
|
+
copyable do
|
332
|
+
disable_all_callbacks_and_observers_except_validate
|
333
|
+
columns({
|
334
|
+
name: :copy,
|
335
|
+
})
|
336
|
+
associations({
|
337
|
+
copyable_pet_sitting_patronages: :copy,
|
338
|
+
})
|
339
|
+
end
|
340
|
+
end
|
341
|
+
undefine_copyable_in CopyablePetSittingPatronage
|
342
|
+
class CopyablePetSittingPatronage < ActiveRecord::Base
|
343
|
+
undef create_copy!
|
344
|
+
# MISSING copyable do
|
345
|
+
# disable_all_callbacks_and_observers_except_validate
|
346
|
+
# columns({
|
347
|
+
# copyable_pet_id: :copy,
|
348
|
+
# copyable_pet_sitter_id: :copy,
|
349
|
+
# })
|
350
|
+
# associations({
|
351
|
+
# })
|
352
|
+
# end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
it 'should raise an informative error' do
|
356
|
+
pet1 = CopyablePet.create!(name: 'Pet1', kind: 'cat', birth_year: 2010)
|
357
|
+
sitter1 = CopyablePetSitter.create!(name: 'Sitter1')
|
358
|
+
patronage1 = CopyablePetSittingPatronage.create!(
|
359
|
+
copyable_pet_id: pet1.id,
|
360
|
+
copyable_pet_sitter_id: sitter1.id)
|
361
|
+
expect {
|
362
|
+
sitter1.create_copy!
|
363
|
+
}.to raise_error(Copyable::CopyableError)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|