amoeba 1.2.1 → 3.2.0

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.
@@ -0,0 +1,19 @@
1
+ module Amoeba
2
+ module Macros
3
+ class HasAndBelongsToMany < ::Amoeba::Macros::Base
4
+ def follow(relation_name, _association)
5
+ clone = @cloner.amoeba.clones.include?(relation_name.to_sym)
6
+ @old_object.__send__(relation_name).each do |old_obj|
7
+ fill_relation(relation_name, old_obj, clone)
8
+ end
9
+ end
10
+
11
+ def fill_relation(relation_name, old_obj, clone)
12
+ # associate this new child to the new parent object
13
+ old_obj = old_obj.amoeba_dup if clone
14
+ relation_name = remapped_relation_name(relation_name)
15
+ @new_object.__send__(relation_name) << old_obj
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ module Amoeba
2
+ module Macros
3
+ class HasMany < ::Amoeba::Macros::Base
4
+ def follow(relation_name, association)
5
+ if @cloner.amoeba.clones.include?(relation_name.to_sym)
6
+ follow_with_clone(relation_name)
7
+ else
8
+ follow_without_clone(relation_name, association)
9
+ end
10
+ end
11
+
12
+ def follow_with_clone(relation_name)
13
+ # This is a M:M "has many through" where we
14
+ # actually copy and reassociate the new children
15
+ # rather than only maintaining the associations
16
+ @old_object.__send__(relation_name).each do |old_obj|
17
+ relation_name = remapped_relation_name(relation_name)
18
+ # associate this new child to the new parent object
19
+ @new_object.__send__(relation_name) << old_obj.amoeba_dup
20
+ end
21
+ end
22
+
23
+ def follow_without_clone(relation_name, association)
24
+ # This is a regular 1:M "has many"
25
+ #
26
+ # copying the children of the regular has many will
27
+ # effectively do what is desired anyway, the through
28
+ # association is really just for convenience usage
29
+ # on the model
30
+ return if association.is_a?(ActiveRecord::Reflection::ThroughReflection)
31
+
32
+ @old_object.__send__(relation_name).each do |old_obj|
33
+ copy_of_obj = old_obj.amoeba_dup(@options)
34
+ copy_of_obj[:"#{association.foreign_key}"] = nil
35
+ relation_name = remapped_relation_name(relation_name)
36
+ # associate this new child to the new parent object
37
+ @new_object.__send__(relation_name) << copy_of_obj
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module Amoeba
2
+ module Macros
3
+ class HasOne < ::Amoeba::Macros::Base
4
+ def follow(relation_name, association)
5
+ return if association.is_a?(::ActiveRecord::Reflection::ThroughReflection)
6
+ old_obj = @old_object.__send__(relation_name)
7
+ return unless old_obj
8
+ copy_of_obj = old_obj.amoeba_dup(@options)
9
+ copy_of_obj[:"#{association.foreign_key}"] = nil
10
+ relation_name = remapped_relation_name(relation_name)
11
+ @new_object.__send__(:"#{relation_name}=", copy_of_obj)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module Amoeba
2
- VERSION = "1.2.1"
2
+ VERSION = '3.2.0'
3
3
  end
@@ -1,18 +1,23 @@
1
- require 'active_record'
2
1
  require 'spec_helper'
3
2
 
4
- describe "amoeba" do
5
- context "dup" do
6
- it "duplicates associated child records" do
3
+ describe 'amoeba' do
4
+ context 'dup' do
5
+ before :each do
6
+ require ::File.dirname(__FILE__) + '/../support/data.rb'
7
+ end
8
+
9
+ let(:first_product) { Product.find(1) }
10
+
11
+ it 'duplicates associated child records' do
7
12
  # Posts {{{
8
- old_post = Post.find(1)
9
- old_post.comments.map(&:contents).include?("I love it!").should be true
13
+ old_post = ::Post.find(1)
14
+ expect(old_post.comments.map(&:contents).include?('I love it!')).to be_truthy
10
15
 
11
16
  old_post.class.amoeba do
12
- prepend :contents => "Here's a copy: "
17
+ prepend contents: "Here's a copy: "
13
18
  end
14
19
 
15
- new_post = old_post.dup
20
+ new_post = old_post.amoeba_dup
16
21
 
17
22
  start_account_count = Account.all.count
18
23
  start_history_count = History.all.count
@@ -27,18 +32,16 @@ describe "amoeba" do
27
32
  start_postconfig_count = PostConfig.all.count
28
33
  start_postwidget_count = PostWidget.all.count
29
34
  start_superkitten_count = Superkitten.all.count
30
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS tag_count FROM posts_tags')
31
- start_posttag_count = rs["tag_count"]
32
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS note_count FROM notes_posts')
33
- start_postnote_count = rs["note_count"]
34
-
35
- new_post.save
36
- new_post.errors.messages.length.should == 0
37
-
38
- end_account_count = Account.all.count
39
- end_history_count = History.all.count
40
- end_cat_count = Category.all.count
41
- end_supercat_count = Supercat.all.count
35
+ start_posttag_count = Post.tag_count
36
+ start_postnote_count = Post.note_count
37
+
38
+ expect(new_post.save!).to be_truthy
39
+ expect(new_post.title).to eq("Copy of #{old_post.title}")
40
+
41
+ end_account_count = Account.count
42
+ end_history_count = History.count
43
+ end_cat_count = Category.count
44
+ end_supercat_count = Supercat.count
42
45
  end_tag_count = Tag.all.count
43
46
  end_note_count = Note.all.count
44
47
  end_widget_count = Widget.all.count
@@ -48,132 +51,354 @@ describe "amoeba" do
48
51
  end_postconfig_count = PostConfig.all.count
49
52
  end_postwidget_count = PostWidget.all.count
50
53
  end_superkitten_count = Superkitten.all.count
51
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS tag_count FROM posts_tags')
52
- end_posttag_count = rs["tag_count"]
53
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS note_count FROM notes_posts')
54
- end_postnote_count = rs["note_count"]
55
-
56
- end_tag_count.should == start_tag_count
57
- end_cat_count.should == start_cat_count
58
- end_account_count.should == start_account_count * 2
59
- end_history_count.should == start_history_count * 2
60
- end_supercat_count.should == start_supercat_count * 2
61
- end_post_count.should == start_post_count * 2
62
- end_comment_count.should == (start_comment_count * 2) + 2
63
- end_rating_count.should == start_rating_count * 2
64
- end_postconfig_count.should == start_postconfig_count * 2
65
- end_posttag_count.should == start_posttag_count * 2
66
- end_widget_count.should == start_widget_count * 2
67
- end_postwidget_count.should == start_postwidget_count * 2
68
- end_note_count.should == start_note_count * 2
69
- end_postnote_count.should == start_postnote_count * 2
70
- end_superkitten_count.should == start_superkitten_count * 2
71
-
72
- new_post.supercats.map(&:ramblings).include?("Copy of zomg").should be true
73
- new_post.supercats.map(&:other_ramblings).uniq.length.should == 1
74
- new_post.supercats.map(&:other_ramblings).uniq.include?("La la la").should be true
75
- new_post.title.should == "Copy of #{old_post.title}"
76
- new_post.contents.should == "Here's a copy: #{old_post.contents.gsub(/dog/, 'cat')} (copied version)"
77
- new_post.comments.length.should == 5
78
- new_post.comments.select{ |c| c.nerf == 'ratatat' && c.contents.nil? }.length.should == 1
79
- new_post.comments.select{ |c| c.nerf == 'ratatat' }.length.should == 2
80
- new_post.comments.select{ |c| c.nerf == 'bonk' }.length.should == 1
81
- new_post.comments.select{ |c| c.nerf == 'bonkers' && c.contents.nil? }.length.should == 1
54
+ end_posttag_count = Post.tag_count
55
+ end_postnote_count = Post.note_count
56
+
57
+ expect(end_tag_count).to eq(start_tag_count)
58
+ expect(end_cat_count).to eq(start_cat_count)
59
+ expect(end_account_count).to eq(start_account_count * 2)
60
+ expect(end_history_count).to eq(start_history_count * 2)
61
+ expect(end_supercat_count).to eq(start_supercat_count * 2)
62
+ expect(end_post_count).to eq(start_post_count * 2)
63
+ expect(end_comment_count).to eq((start_comment_count * 2) + 2)
64
+ expect(end_rating_count).to eq(start_rating_count * 2)
65
+ expect(end_postconfig_count).to eq(start_postconfig_count * 2)
66
+ expect(end_posttag_count).to eq(start_posttag_count * 2)
67
+ expect(end_widget_count).to eq(start_widget_count * 2)
68
+ expect(end_postwidget_count).to eq(start_postwidget_count * 2)
69
+ expect(end_note_count).to eq(start_note_count * 2)
70
+ expect(end_postnote_count).to eq(start_postnote_count * 2)
71
+ expect(end_superkitten_count).to eq(start_superkitten_count * 2)
72
+
73
+ expect(new_post.supercats.map(&:ramblings)).to include('Copy of zomg')
74
+ expect(new_post.supercats.map(&:other_ramblings).uniq.length).to eq(1)
75
+ expect(new_post.supercats.map(&:other_ramblings).uniq).to include('La la la')
76
+ expect(new_post.contents).to eq("Here's a copy: #{old_post.contents.gsub(/dog/, 'cat')} (copied version)")
77
+ expect(new_post.comments.length).to eq(5)
78
+ expect(new_post.comments.select { |c| c.nerf == 'ratatat' && c.contents.nil? }.length).to eq(1)
79
+ expect(new_post.comments.select { |c| c.nerf == 'ratatat' }.length).to eq(2)
80
+ expect(new_post.comments.select { |c| c.nerf == 'bonk' }.length).to eq(1)
81
+ expect(new_post.comments.select { |c| c.nerf == 'bonkers' && c.contents.nil? }.length).to eq(1)
82
82
 
83
83
  new_post.widgets.map(&:id).each do |id|
84
- old_post.widgets.map(&:id).include?(id).should_not be true
84
+ expect(old_post.widgets.map(&:id)).not_to include(id)
85
85
  end
86
+
87
+ expect(new_post.custom_things.length).to eq(3)
88
+ expect(new_post.custom_things.select { |ct| ct.value == [] }.length).to eq(1)
89
+ expect(new_post.custom_things.select { |ct| ct.value == [1, 2] }.length).to eq(1)
90
+ expect(new_post.custom_things.select { |ct| ct.value == [78] }.length).to eq(1)
86
91
  # }}}
87
92
  # Author {{{
88
93
  old_author = Author.find(1)
89
- new_author = old_author.dup
90
- new_author.save
91
- new_author.errors.messages.length.should == 0
94
+ new_author = old_author.amoeba_dup
95
+ new_author.save!
96
+ expect(new_author.errors.messages).to be_empty
97
+ expect(new_author.posts.first.custom_things.length).to eq(3)
98
+ expect(new_author.posts.first.custom_things.select { |ct| ct.value == [] }.length).to eq(1)
99
+ expect(new_author.posts.first.custom_things.select { |ct| ct.value == [1, 2] }.length).to eq(1)
100
+ expect(new_author.posts.first.custom_things.select { |ct| ct.value == [78] }.length).to eq(1)
92
101
  # }}}
93
102
  # Products {{{
94
103
  # Base Class {{{
95
- old_product = Product.find(1)
96
104
 
97
- start_image_count = Image.where(:product_id => old_product.id).count
105
+ start_image_count = first_product.images.count
98
106
  start_section_count = Section.all.length
99
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', old_product.id)
100
- start_prodsection_count = rs["section_count"]
107
+ start_prodsection_count = first_product.section_count
101
108
 
102
- new_product = old_product.dup
109
+ new_product = first_product.amoeba_dup
103
110
  new_product.save
104
- new_product.errors.messages.length.should == 0
111
+ expect(new_product.errors.messages).to be_empty
105
112
 
106
- end_image_count = Image.where(:product_id => old_product.id).count
107
- end_newimage_count = Image.where(:product_id => new_product.id).count
113
+ end_image_count = first_product.images.count
114
+ end_newimage_count = new_product.images.count
108
115
  end_section_count = Section.all.length
109
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', 1)
110
- end_prodsection_count = rs["section_count"]
111
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', new_product.id)
112
- end_newprodsection_count = rs["section_count"]
113
-
114
- end_image_count.should == start_image_count
115
- end_newimage_count.should == start_image_count
116
- end_section_count.should == start_section_count
117
- end_prodsection_count.should == start_prodsection_count
118
- end_newprodsection_count.should == start_prodsection_count
116
+ end_prodsection_count = first_product.section_count
117
+ end_newprodsection_count = new_product.section_count
118
+
119
+ expect(end_image_count).to eq(start_image_count)
120
+ expect(end_newimage_count).to eq(start_image_count)
121
+ expect(end_section_count).to eq(start_section_count)
122
+ expect(end_prodsection_count).to eq(start_prodsection_count)
123
+ expect(end_newprodsection_count).to eq(start_prodsection_count)
119
124
  # }}}
120
125
 
121
126
  # Inherited Class {{{
122
127
  # Shirt {{{
123
128
  old_product = Shirt.find(2)
124
129
 
125
- start_image_count = Image.where(:product_id => old_product.id).count
126
- start_section_count = Section.all.length
127
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', old_product.id)
128
- start_prodsection_count = rs["section_count"]
130
+ start_image_count = old_product.images.count
131
+ start_section_count = Section.count
132
+ start_prodsection_count = old_product.section_count
129
133
 
130
- new_product = old_product.dup
134
+ new_product = old_product.amoeba_dup
131
135
  new_product.save
132
- new_product.errors.messages.length.should == 0
136
+ expect(new_product.errors.messages).to be_empty
133
137
 
134
- end_image_count = Image.where(:product_id => old_product.id).count
135
- end_newimage_count = Image.where(:product_id => new_product.id).count
136
- end_section_count = Section.all.length
137
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', 1)
138
- end_prodsection_count = rs["section_count"]
139
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', new_product.id)
140
- end_newprodsection_count = rs["section_count"]
141
-
142
- end_image_count.should == start_image_count
143
- end_newimage_count.should == start_image_count
144
- end_section_count.should == start_section_count
145
- end_prodsection_count.should == start_prodsection_count
146
- end_newprodsection_count.should == start_prodsection_count
138
+ end_image_count = old_product.images.count
139
+ end_newimage_count = new_product.images.count
140
+ end_section_count = Section.count
141
+ end_prodsection_count = first_product.section_count
142
+ end_newprodsection_count = new_product.section_count
143
+
144
+ expect(end_image_count).to eq(start_image_count)
145
+ expect(end_newimage_count).to eq(start_image_count)
146
+ expect(end_section_count).to eq(start_section_count)
147
+ expect(end_prodsection_count).to eq(start_prodsection_count)
148
+ expect(end_newprodsection_count).to eq(start_prodsection_count)
147
149
  # }}}
148
150
 
149
151
  # Necklace {{{
150
152
  old_product = Necklace.find(3)
151
153
 
152
- start_image_count = Image.where(:product_id => old_product.id).count
153
- start_section_count = Section.all.length
154
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', old_product.id)
155
- start_prodsection_count = rs["section_count"]
154
+ start_image_count = old_product.images.count
155
+ start_section_count = Section.count
156
+ start_prodsection_count = old_product.section_count
156
157
 
157
- new_product = old_product.dup
158
+ new_product = old_product.amoeba_dup
158
159
  new_product.save
159
- new_product.errors.messages.length.should == 0
160
+ expect(new_product.errors.messages).to be_empty
160
161
 
161
- end_image_count = Image.where(:product_id => old_product.id).count
162
- end_newimage_count = Image.where(:product_id => new_product.id).count
163
- end_section_count = Section.all.length
164
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', 1)
165
- end_prodsection_count = rs["section_count"]
166
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', new_product.id)
167
- end_newprodsection_count = rs["section_count"]
168
-
169
- end_image_count.should == start_image_count
170
- end_newimage_count.should == start_image_count
171
- end_section_count.should == start_section_count
172
- end_prodsection_count.should == start_prodsection_count
173
- end_newprodsection_count.should == start_prodsection_count
162
+ end_image_count = old_product.images.count
163
+ end_newimage_count = new_product.images.count
164
+ end_section_count = Section.count
165
+ end_prodsection_count = first_product.section_count
166
+ end_newprodsection_count = new_product.section_count
167
+
168
+ expect(end_image_count).to eq(start_image_count)
169
+ expect(end_newimage_count).to eq(start_image_count)
170
+ expect(end_section_count).to eq(start_section_count)
171
+ expect(end_prodsection_count).to eq(start_prodsection_count)
172
+ expect(end_newprodsection_count).to eq(start_prodsection_count)
174
173
  # }}}
175
174
  # }}}
176
175
  # }}}
177
176
  end
178
177
  end
178
+
179
+ context 'Using a if condition' do
180
+ before(:all) do
181
+ require ::File.dirname(__FILE__) + '/../support/data.rb'
182
+ end
183
+ before { ::Post.fresh_amoeba }
184
+
185
+ subject { post.amoeba_dup.save! }
186
+ let(:post) { Post.first }
187
+
188
+ it 'includes an association with truthy condition' do
189
+ ::Post.amoeba do
190
+ include_association :comments, if: :truthy?
191
+ end
192
+ expect { subject }.to change { Comment.count }.by(3)
193
+ end
194
+
195
+ it 'does not include an association with a falsey condition' do
196
+ ::Post.amoeba do
197
+ include_association :comments, if: :falsey?
198
+ end
199
+ expect { subject }.not_to change { Comment.count }
200
+ end
201
+
202
+ it 'excludes an association with a truthy condition' do
203
+ ::Post.amoeba do
204
+ exclude_association :comments, if: :truthy?
205
+ end
206
+ expect { subject }.not_to change { Comment.count }
207
+ end
208
+
209
+ it 'does not exclude an association with a falsey condition' do
210
+ ::Post.amoeba do
211
+ exclude_association :comments, if: :falsey?
212
+ end
213
+ expect { subject }.to change { Comment.count }.by(3)
214
+ end
215
+
216
+ it 'includes associations from a given array with a truthy condition' do
217
+ ::Post.amoeba do
218
+ include_association [:comments], if: :truthy?
219
+ end
220
+ expect { subject }.to change { Comment.count }.by(3)
221
+ end
222
+
223
+ it 'does not include associations from a given array with a falsey condition' do
224
+ ::Post.amoeba do
225
+ include_association [:comments], if: :falsey?
226
+ end
227
+ expect { subject }.not_to change { Comment.count }
228
+ end
229
+
230
+ it 'does exclude associations from a given array with a truthy condition' do
231
+ ::Post.amoeba do
232
+ exclude_association [:comments], if: :truthy?
233
+ end
234
+ expect { subject }.not_to change { Comment.count }
235
+ end
236
+
237
+ it 'does not exclude associations from a given array with a falsey condition' do
238
+ ::Post.amoeba do
239
+ exclude_association [:comments], if: :falsey?
240
+ end
241
+ expect { subject }.to change { Comment.count }.by(3)
242
+ end
243
+ end
244
+
245
+ context 'override' do
246
+ before :each do
247
+ ::Image.fresh_amoeba
248
+ ::Image.amoeba do
249
+ override ->(old, new) { new.product_id = 13 if old.filename == 'test.jpg' }
250
+ end
251
+ end
252
+
253
+ it 'should override fields' do
254
+ image = ::Image.create(filename: 'test.jpg', product_id: 12)
255
+ image_dup = image.amoeba_dup
256
+ expect(image_dup.save).to be_truthy
257
+ expect(image_dup.product_id).to eq(13)
258
+ end
259
+
260
+ it 'should not override fields' do
261
+ image = ::Image.create(filename: 'test2.jpg', product_id: 12)
262
+ image_dup = image.amoeba_dup
263
+ expect(image_dup.save).to be_truthy
264
+ expect(image_dup.product_id).to eq(12)
265
+ end
266
+ end
267
+
268
+ context 'nullify' do
269
+ before :each do
270
+ ::Image.fresh_amoeba
271
+ ::Image.amoeba do
272
+ nullify :product_id
273
+ end
274
+ end
275
+
276
+ let(:image) { ::Image.create(filename: 'test.jpg', product_id: 12) }
277
+ let(:image_dup) { image.amoeba_dup }
278
+
279
+ it 'should nullify fields' do
280
+ expect(image_dup.save).to be_truthy
281
+ expect(image_dup.product_id).to be_nil
282
+ end
283
+ end
284
+
285
+ context 'strict propagate' do
286
+ it 'should call #reset_amoeba' do
287
+ expect(::SuperBlackBox).to receive(:reset_amoeba).and_call_original
288
+ box = ::SuperBlackBox.create(title: 'Super Black Box', price: 9.99, length: 1, metal: '1')
289
+ new_box = box.amoeba_dup
290
+ expect(new_box.save).to be_truthy
291
+ end
292
+ end
293
+
294
+ context 'remapping and custom dup method' do
295
+ let(:prototype) { ObjectPrototype.new }
296
+
297
+ context 'through' do
298
+ it do
299
+ real_object = prototype.amoeba_dup
300
+ expect(real_object).to be_a(::RealObject)
301
+ end
302
+ end
303
+
304
+ context 'remapper' do
305
+ it do
306
+ prototype.subobject_prototypes << SubobjectPrototype.new
307
+ real_object = prototype.amoeba_dup
308
+ expect(real_object.subobjects.length).to eq(1)
309
+ end
310
+ end
311
+ end
312
+
313
+ context 'preprocessing fields' do
314
+ subject { super_admin.amoeba_dup }
315
+ let(:super_admin) { ::SuperAdmin.create!(email: 'user@example.com', active: true, password: 'password') }
316
+
317
+ it 'should accept "set" to set false to attribute' do
318
+ expect(subject.active).to be false
319
+ end
320
+
321
+ it 'should skip "prepend" if it equal to false' do
322
+ expect(subject.password).to eq('password')
323
+ end
324
+ end
325
+
326
+ context 'inheritance' do
327
+ let(:box) { Box.create }
328
+
329
+ it 'does not fail with a deep inheritance' do
330
+ sub_sub_product = BoxSubSubProduct.create(title: 'Awesome shoes')
331
+ another_product = BoxAnotherProduct.create(title: 'Cleaning product')
332
+ sub_sub_product.update(box: box, another_product: another_product)
333
+ expect(box.sub_products.first.another_product.title).to eq('Cleaning product')
334
+ expect(box.amoeba_dup.sub_products.first.another_product.title).to eq('Cleaning product')
335
+ end
336
+ end
337
+
338
+ context 'inheritance extended' do
339
+ let(:stage) do
340
+ stage = CustomStage.new(title: 'My Stage', external_id: 213)
341
+ stage.listeners.build(name: 'John')
342
+ stage.listeners.build(name: 'Helen')
343
+ stage.specialists.build(name: 'Jack')
344
+ stage.custom_rules.build(description: 'Kill all humans')
345
+ stage.save!
346
+ stage
347
+ end
348
+
349
+ subject { stage.amoeba_dup }
350
+
351
+ it 'contains parent association and own associations', :aggregate_failures do
352
+ subject
353
+ expect { subject.save! }.to change(Listener, :count).by(2).
354
+ and change(Specialist, :count).by(1).
355
+ and change(CustomRule, :count).by(1)
356
+
357
+ expect(subject.title).to eq 'My Stage'
358
+ expect(subject.external_id).to be_nil
359
+ expect(subject.listeners.find_by(name: 'John')).to_not be_nil
360
+ expect(subject.listeners.find_by(name: 'Helen')).to_not be_nil
361
+ expect(subject.specialists.find_by(name: 'Jack')).to_not be_nil
362
+ expect(subject.custom_rules.first.description).to eq 'Kill all humans'
363
+ end
364
+ end
365
+
366
+ context 'polymorphic' do
367
+ let(:company) { Company.find_by(name: 'ABC Industries') }
368
+ let(:new_company) { company.amoeba_dup }
369
+
370
+ it 'does not fail with a deep inheritance' do
371
+ # employee = company.employees.where(name:'Joe').first
372
+ start_company_count = Company.count
373
+ start_customer_count = Customer.count
374
+ start_employee_count = Employee.count
375
+ start_address_count = Address.count
376
+ start_photo_count = Photo.count
377
+ new_company.name = "Copy of #{new_company.name}"
378
+ new_company.save
379
+ expect(Company.count).to eq(start_company_count + 1)
380
+ expect(Customer.count).to eq(start_customer_count + 1)
381
+ expect(Employee.count).to eq(start_employee_count + 1)
382
+ expect(Address.count).to eq(start_address_count + 4)
383
+ expect(Photo.count).to eq(start_photo_count + 2)
384
+
385
+ new_company.reload # fully reload from database
386
+ new_company_employees = new_company.employees
387
+ expect(new_company_employees.count).to eq(1)
388
+ new_company_employee_joe = new_company_employees.find_by(name: 'Joe')
389
+ expect(new_company_employee_joe.photos.count).to eq(1)
390
+ expect(new_company_employee_joe.photos.first.size).to eq(12_345)
391
+ expect(new_company_employee_joe.addresses.count).to eq(2)
392
+ expect(new_company_employee_joe.addresses.where(street: '123 My Street').count).to eq(1)
393
+ expect(new_company_employee_joe.addresses.where(street: '124 My Street').count).to eq(1)
394
+ new_company_customers = new_company.customers
395
+ expect(new_company_customers.count).to eq(1)
396
+ new_company_customer_my = new_company_customers.where(email: 'my@email.address').first
397
+ expect(new_company_customer_my.photos.count).to eq(1)
398
+ expect(new_company_customer_my.photos.first.size).to eq(54_321)
399
+ expect(new_company_customer_my.addresses.count).to eq(2)
400
+ expect(new_company_customer_my.addresses.where(street: '321 My Street').count).to eq(1)
401
+ expect(new_company_customer_my.addresses.where(street: '321 My Drive').count).to eq(1)
402
+ end
403
+ end
179
404
  end