amoeba 3.0.0 → 3.1.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.
@@ -16,6 +16,11 @@ module Amoeba
16
16
  @config
17
17
  end
18
18
 
19
+ def reset_amoeba(&block)
20
+ @config_block = block if block_given?
21
+ @config = Amoeba::Config.new(self)
22
+ end
23
+
19
24
  def amoeba_block
20
25
  @config_block
21
26
  end
@@ -9,10 +9,11 @@ module Amoeba
9
9
  def_delegators :old_object, :_parent_amoeba, :_amoeba_settings,
10
10
  :_parent_amoeba_settings
11
11
 
12
- def_delegators :object_klass, :amoeba, :fresh_amoeba
12
+ def_delegators :object_klass, :amoeba, :fresh_amoeba, :reset_amoeba
13
13
 
14
14
  def initialize(object, options = {})
15
- @old_object, @options = object, options
15
+ @old_object = object
16
+ @options = options
16
17
  @object_klass = @old_object.class
17
18
  inherit_parent_settings
18
19
  @new_object = object.__send__(amoeba.dup_method)
@@ -40,12 +41,13 @@ module Amoeba
40
41
  end
41
42
 
42
43
  def inherit_submissive_parent_settings
43
- fresh_amoeba(&_parent_amoeba_settings)
44
+ reset_amoeba(&_amoeba_settings)
45
+ amoeba(&_parent_amoeba_settings)
44
46
  amoeba(&_amoeba_settings)
45
47
  end
46
48
 
47
49
  def inherit_parent_settings
48
- return if amoeba.enabled || !_parent_amoeba.inherit
50
+ return if !_parent_amoeba.inherit
49
51
  return unless %w(strict relaxed submissive).include?(parenting_style.to_s)
50
52
  __send__("inherit_#{parenting_style}_parent_settings".to_sym)
51
53
  end
@@ -64,19 +66,21 @@ module Amoeba
64
66
  # table from copying so we don't end up with the new
65
67
  # and old children on the copy
66
68
  return unless association.macro == :has_many ||
67
- association.is_a?(::ActiveRecord::Reflection::ThroughReflection)
69
+ association.is_a?(::ActiveRecord::Reflection::ThroughReflection)
68
70
  amoeba.exclude_association(association.options[:through])
69
71
  end
70
72
 
71
73
  def follow_only_includes
72
- amoeba.includes.each do |include|
74
+ amoeba.includes.each do |include, options|
75
+ next if options[:if] && !@old_object.send(options[:if])
73
76
  follow_association(include, @object_klass.reflect_on_association(include))
74
77
  end
75
78
  end
76
79
 
77
80
  def follow_all_except_excludes
78
81
  @object_klass.reflections.each do |name, association|
79
- next if amoeba.excludes.include?(name.to_sym)
82
+ exclude = amoeba.excludes[name.to_sym]
83
+ next if exclude && (exclude.blank? || @old_object.send(exclude[:if]))
80
84
  follow_association(name, association)
81
85
  end
82
86
  end
@@ -88,9 +92,9 @@ module Amoeba
88
92
  end
89
93
 
90
94
  def apply_associations
91
- if amoeba.includes.size > 0
95
+ if amoeba.includes.present?
92
96
  follow_only_includes
93
- elsif amoeba.excludes.size > 0
97
+ elsif amoeba.excludes.present?
94
98
  follow_all_except_excludes
95
99
  else
96
100
  follow_all
@@ -110,7 +114,7 @@ module Amoeba
110
114
 
111
115
  def process_overrides
112
116
  amoeba.overrides.each do |block|
113
- block.call(@new_object, @new_object)
117
+ block.call(@old_object, @new_object)
114
118
  end
115
119
  end
116
120
 
@@ -124,7 +128,7 @@ module Amoeba
124
128
  def process_coercions
125
129
  # prepend any extra strings to indicate uniqueness of the new record(s)
126
130
  amoeba.coercions.each do |field, coercion|
127
- @new_object[field] = "#{coercion}"
131
+ @new_object[field] = coercion.to_s
128
132
  end
129
133
  end
130
134
 
@@ -8,8 +8,8 @@ module Amoeba
8
8
  raised: false,
9
9
  dup_method: :dup,
10
10
  remap_method: nil,
11
- includes: [],
12
- excludes: [],
11
+ includes: {},
12
+ excludes: {},
13
13
  clones: [],
14
14
  customizations: [],
15
15
  overrides: [],
@@ -40,7 +40,7 @@ module Amoeba
40
40
  DEFAULTS.freeze
41
41
 
42
42
  DEFAULTS.each do |key, value|
43
- value.freeze
43
+ value.freeze if value.is_a?(Array) || value.is_a?(Hash)
44
44
  class_eval <<-EOS, __FILE__, __LINE__ + 1
45
45
  def #{key} # def enabled
46
46
  @config[:#{key}] # @config[:enabled]
@@ -69,15 +69,15 @@ module Amoeba
69
69
 
70
70
  def propagate(style = :submissive)
71
71
  @config[:parenting] ||= style
72
- @config[:inherit] = true
72
+ @config[:inherit] = true
73
73
  end
74
74
 
75
75
  def push_value_to_array(value, key)
76
76
  res = @config[key]
77
77
  if value.is_a?(::Array)
78
78
  res = value
79
- else
80
- res << value if value
79
+ elsif value
80
+ res << value
81
81
  end
82
82
  @config[key] = res.uniq
83
83
  end
@@ -107,37 +107,45 @@ module Amoeba
107
107
  @config[config_key][key] = val if val || (!val.nil? && config_key == :coercions)
108
108
  end
109
109
 
110
- def include_association(value = nil)
111
- @config[:enabled] = true
112
- @config[:excludes] = []
113
- push_value_to_array(value, :includes)
110
+ def include_association(value = nil, options = {})
111
+ enable
112
+ @config[:excludes] = {}
113
+ push_value_to_hash({ value => options }, :includes)
114
+ end
115
+
116
+ def include_associations(*values)
117
+ values.flatten.each { |v| include_association(v) }
114
118
  end
115
119
 
116
- # TODO remove this method in v3.0.0
120
+ # TODO: remove this method in v3.0.0
117
121
  def include_field(value = nil)
118
- warn "include_field is deprecated and will be removed in version 3.0.0; please use include_association instead"
122
+ warn 'include_field is deprecated and will be removed in version 3.0.0; please use include_association instead'
119
123
  include_association(value)
120
124
  end
121
125
 
122
- def exclude_association(value = nil)
123
- @config[:enabled] = true
124
- @config[:includes] = []
125
- push_value_to_array(value, :excludes)
126
+ def exclude_association(value = nil, options = {})
127
+ enable
128
+ @config[:includes] = {}
129
+ push_value_to_hash({ value => options }, :excludes)
126
130
  end
127
131
 
128
- # TODO remove this method in v3.0.0
132
+ def exclude_associations(*values)
133
+ values.flatten.each { |v| exclude_association(v) }
134
+ end
135
+
136
+ # TODO: remove this method in v3.0.0
129
137
  def exclude_field(value = nil)
130
- warn "exclude_field is deprecated and will be removed in version 3.0.0; please use exclude_association instead"
138
+ warn 'exclude_field is deprecated and will be removed in version 3.0.0; please use exclude_association instead'
131
139
  exclude_association(value)
132
140
  end
133
141
 
134
142
  def clone(value = nil)
135
- @config[:enabled] = true
143
+ enable
136
144
  push_value_to_array(value, :clones)
137
145
  end
138
146
 
139
147
  def recognize(value = nil)
140
- @config[:enabled] = true
148
+ enable
141
149
  push_value_to_array(value, :known_macros)
142
150
  end
143
151
 
@@ -1,3 +1,3 @@
1
1
  module Amoeba
2
- VERSION = '3.0.0'
2
+ VERSION = '3.1.0'
3
3
  end
@@ -5,6 +5,9 @@ describe 'amoeba' do
5
5
  before :each do
6
6
  require ::File.dirname(__FILE__) + '/../support/data.rb'
7
7
  end
8
+
9
+ let(:first_product) { Product.find(1) }
10
+
8
11
  it 'duplicates associated child records' do
9
12
  # Posts {{{
10
13
  old_post = ::Post.find(1)
@@ -29,18 +32,16 @@ describe 'amoeba' do
29
32
  start_postconfig_count = PostConfig.all.count
30
33
  start_postwidget_count = PostWidget.all.count
31
34
  start_superkitten_count = Superkitten.all.count
32
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS tag_count FROM posts_tags')
33
- start_posttag_count = rs['tag_count']
34
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS note_count FROM notes_posts')
35
- start_postnote_count = rs['note_count']
35
+ start_posttag_count = Post.tag_count
36
+ start_postnote_count = Post.note_count
36
37
 
37
38
  expect(new_post.save!).to be_truthy
38
39
  expect(new_post.title).to eq("Copy of #{old_post.title}")
39
40
 
40
- end_account_count = Account.all.count
41
- end_history_count = History.all.count
42
- end_cat_count = Category.all.count
43
- end_supercat_count = Supercat.all.count
41
+ end_account_count = Account.count
42
+ end_history_count = History.count
43
+ end_cat_count = Category.count
44
+ end_supercat_count = Supercat.count
44
45
  end_tag_count = Tag.all.count
45
46
  end_note_count = Note.all.count
46
47
  end_widget_count = Widget.all.count
@@ -50,10 +51,8 @@ describe 'amoeba' do
50
51
  end_postconfig_count = PostConfig.all.count
51
52
  end_postwidget_count = PostWidget.all.count
52
53
  end_superkitten_count = Superkitten.all.count
53
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS tag_count FROM posts_tags')
54
- end_posttag_count = rs['tag_count']
55
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS note_count FROM notes_posts')
56
- end_postnote_count = rs['note_count']
54
+ end_posttag_count = Post.tag_count
55
+ end_postnote_count = Post.note_count
57
56
 
58
57
  expect(end_tag_count).to eq(start_tag_count)
59
58
  expect(end_cat_count).to eq(start_cat_count)
@@ -71,9 +70,9 @@ describe 'amoeba' do
71
70
  expect(end_postnote_count).to eq(start_postnote_count * 2)
72
71
  expect(end_superkitten_count).to eq(start_superkitten_count * 2)
73
72
 
74
- expect(new_post.supercats.map(&:ramblings).include?('Copy of zomg')).to be true
73
+ expect(new_post.supercats.map(&:ramblings)).to include('Copy of zomg')
75
74
  expect(new_post.supercats.map(&:other_ramblings).uniq.length).to eq(1)
76
- expect(new_post.supercats.map(&:other_ramblings).uniq.include?('La la la')).to be true
75
+ expect(new_post.supercats.map(&:other_ramblings).uniq).to include('La la la')
77
76
  expect(new_post.contents).to eq("Here's a copy: #{old_post.contents.gsub(/dog/, 'cat')} (copied version)")
78
77
  expect(new_post.comments.length).to eq(5)
79
78
  expect(new_post.comments.select { |c| c.nerf == 'ratatat' && c.contents.nil? }.length).to eq(1)
@@ -82,7 +81,7 @@ describe 'amoeba' do
82
81
  expect(new_post.comments.select { |c| c.nerf == 'bonkers' && c.contents.nil? }.length).to eq(1)
83
82
 
84
83
  new_post.widgets.map(&:id).each do |id|
85
- expect(old_post.widgets.map(&:id).include?(id)).not_to be true
84
+ expect(old_post.widgets.map(&:id)).not_to include(id)
86
85
  end
87
86
 
88
87
  expect(new_post.custom_things.length).to eq(3)
@@ -94,7 +93,7 @@ describe 'amoeba' do
94
93
  old_author = Author.find(1)
95
94
  new_author = old_author.amoeba_dup
96
95
  new_author.save!
97
- expect(new_author.errors.messages.length).to eq(0)
96
+ expect(new_author.errors.messages).to be_empty
98
97
  expect(new_author.posts.first.custom_things.length).to eq(3)
99
98
  expect(new_author.posts.first.custom_things.select { |ct| ct.value == [] }.length).to eq(1)
100
99
  expect(new_author.posts.first.custom_things.select { |ct| ct.value == [1, 2] }.length).to eq(1)
@@ -102,24 +101,20 @@ describe 'amoeba' do
102
101
  # }}}
103
102
  # Products {{{
104
103
  # Base Class {{{
105
- old_product = Product.find(1)
106
104
 
107
- start_image_count = Image.where(product_id: old_product.id).count
105
+ start_image_count = first_product.images.count
108
106
  start_section_count = Section.all.length
109
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', old_product.id)
110
- start_prodsection_count = rs['section_count']
107
+ start_prodsection_count = first_product.section_count
111
108
 
112
- new_product = old_product.amoeba_dup
109
+ new_product = first_product.amoeba_dup
113
110
  new_product.save
114
- expect(new_product.errors.messages.length).to eq(0)
111
+ expect(new_product.errors.messages).to be_empty
115
112
 
116
- end_image_count = Image.where(product_id: old_product.id).count
117
- 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
118
115
  end_section_count = Section.all.length
119
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', 1)
120
- end_prodsection_count = rs['section_count']
121
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', new_product.id)
122
- end_newprodsection_count = rs['section_count']
116
+ end_prodsection_count = first_product.section_count
117
+ end_newprodsection_count = new_product.section_count
123
118
 
124
119
  expect(end_image_count).to eq(start_image_count)
125
120
  expect(end_newimage_count).to eq(start_image_count)
@@ -132,22 +127,19 @@ describe 'amoeba' do
132
127
  # Shirt {{{
133
128
  old_product = Shirt.find(2)
134
129
 
135
- start_image_count = Image.where(product_id: old_product.id).count
136
- start_section_count = Section.all.length
137
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', old_product.id)
138
- 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
139
133
 
140
134
  new_product = old_product.amoeba_dup
141
135
  new_product.save
142
- expect(new_product.errors.messages.length).to eq(0)
136
+ expect(new_product.errors.messages).to be_empty
143
137
 
144
- end_image_count = Image.where(product_id: old_product.id).count
145
- end_newimage_count = Image.where(product_id: new_product.id).count
146
- end_section_count = Section.all.length
147
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', 1)
148
- end_prodsection_count = rs['section_count']
149
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', new_product.id)
150
- end_newprodsection_count = rs['section_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
151
143
 
152
144
  expect(end_image_count).to eq(start_image_count)
153
145
  expect(end_newimage_count).to eq(start_image_count)
@@ -159,22 +151,19 @@ describe 'amoeba' do
159
151
  # Necklace {{{
160
152
  old_product = Necklace.find(3)
161
153
 
162
- start_image_count = Image.where(product_id: old_product.id).count
163
- start_section_count = Section.all.length
164
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', old_product.id)
165
- 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
166
157
 
167
158
  new_product = old_product.amoeba_dup
168
159
  new_product.save
169
- expect(new_product.errors.messages.length).to eq(0)
160
+ expect(new_product.errors.messages).to be_empty
170
161
 
171
- end_image_count = Image.where(product_id: old_product.id).count
172
- end_newimage_count = Image.where(product_id: new_product.id).count
173
- end_section_count = Section.all.length
174
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', 1)
175
- end_prodsection_count = rs['section_count']
176
- rs = ActiveRecord::Base.connection.select_one('SELECT COUNT(*) AS section_count FROM products_sections WHERE product_id = ?', new_product.id)
177
- end_newprodsection_count = rs['section_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
178
167
 
179
168
  expect(end_image_count).to eq(start_image_count)
180
169
  expect(end_newimage_count).to eq(start_image_count)
@@ -186,23 +175,60 @@ describe 'amoeba' do
186
175
  # }}}
187
176
  end
188
177
  end
178
+
179
+ context 'use if condition in includes and excludes' 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 associations 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 associations with false 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 associations with 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 associations with false 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
+ end
216
+
189
217
  context 'override' do
190
218
  before :each do
191
219
  ::Image.fresh_amoeba
192
220
  ::Image.amoeba do
193
- override ->(old, new) {
194
- if old.filename == 'test.jpg'
195
- new.product_id = 13
196
- end
197
- }
221
+ override ->(old, new) { new.product_id = 13 if old.filename == 'test.jpg' }
198
222
  end
199
223
  end
224
+
200
225
  it 'should override fields' do
201
226
  image = ::Image.create(filename: 'test.jpg', product_id: 12)
202
227
  image_dup = image.amoeba_dup
203
228
  expect(image_dup.save).to be_truthy
204
229
  expect(image_dup.product_id).to eq(13)
205
230
  end
231
+
206
232
  it 'should not override fields' do
207
233
  image = ::Image.create(filename: 'test2.jpg', product_id: 12)
208
234
  image_dup = image.amoeba_dup
@@ -218,17 +244,19 @@ describe 'amoeba' do
218
244
  nullify :product_id
219
245
  end
220
246
  end
247
+
248
+ let(:image) { ::Image.create(filename: 'test.jpg', product_id: 12) }
249
+ let(:image_dup) { image.amoeba_dup }
250
+
221
251
  it 'should nullify fields' do
222
- image = ::Image.create(filename: 'test.jpg', product_id: 12)
223
- image_dup = image.amoeba_dup
224
252
  expect(image_dup.save).to be_truthy
225
253
  expect(image_dup.product_id).to be_nil
226
254
  end
227
255
  end
228
256
 
229
257
  context 'strict propagate' do
230
- it 'should call #fresh_amoeba' do
231
- expect(::SuperBlackBox).to receive(:fresh_amoeba).and_call_original
258
+ it 'should call #reset_amoeba' do
259
+ expect(::SuperBlackBox).to receive(:reset_amoeba).and_call_original
232
260
  box = ::SuperBlackBox.create(title: 'Super Black Box', price: 9.99, length: 1, metal: '1')
233
261
  new_box = box.amoeba_dup
234
262
  expect(new_box.save).to be_truthy
@@ -237,12 +265,14 @@ describe 'amoeba' do
237
265
 
238
266
  context 'remapping and custom dup method' do
239
267
  let(:prototype) { ObjectPrototype.new }
268
+
240
269
  context 'through' do
241
270
  it do
242
271
  real_object = prototype.amoeba_dup
243
272
  expect(real_object).to be_a(::RealObject)
244
273
  end
245
274
  end
275
+
246
276
  context 'remapper' do
247
277
  it do
248
278
  prototype.subobject_prototypes << SubobjectPrototype.new
@@ -253,29 +283,94 @@ describe 'amoeba' do
253
283
  end
254
284
 
255
285
  context 'preprocessing fields' do
286
+ subject { super_admin.amoeba_dup }
287
+ let(:super_admin) { ::SuperAdmin.create!(email: 'user@example.com', active: true, password: 'password') }
288
+
256
289
  it 'should accept "set" to set false to attribute' do
257
- super_admin = ::SuperAdmin.create!(email: 'user@example.com', active: true, password: 'password')
258
- clone = super_admin.amoeba_dup
259
- expect(clone.active).to eq(false)
290
+ expect(subject.active).to be false
260
291
  end
292
+
261
293
  it 'should skip "prepend" if it equal to false' do
262
- super_admin = ::SuperAdmin.create!(email: 'user2@example.com', active: true, password: 'password')
263
- clone = super_admin.amoeba_dup
264
- expect(clone.password).to eq('password')
294
+ expect(subject.password).to eq('password')
265
295
  end
266
296
  end
267
297
 
268
298
  context 'inheritance' do
299
+ let(:box) { Box.create }
300
+
269
301
  it 'does not fail with a deep inheritance' do
270
- box = Box.create
271
302
  sub_sub_product = BoxSubSubProduct.create(title: 'Awesome shoes')
272
303
  another_product = BoxAnotherProduct.create(title: 'Cleaning product')
273
- sub_sub_product.box = box
274
- sub_sub_product.another_product = another_product
275
- sub_sub_product.save
304
+ sub_sub_product.update_attributes(box: box, another_product: another_product)
276
305
  expect(box.sub_products.first.another_product.title).to eq('Cleaning product')
277
306
  expect(box.amoeba_dup.sub_products.first.another_product.title).to eq('Cleaning product')
278
307
  end
279
308
  end
280
309
 
310
+ context 'inheritance extended' do
311
+ let(:stage) do
312
+ stage = CustomStage.new(title: 'My Stage', external_id: 213)
313
+ stage.listeners.build(name: 'John')
314
+ stage.listeners.build(name: 'Helen')
315
+ stage.specialists.build(name: 'Jack')
316
+ stage.custom_rules.build(description: 'Kill all humans')
317
+ stage.save!
318
+ stage
319
+ end
320
+
321
+ subject { stage.amoeba_dup }
322
+
323
+ it "contains parent association and own associations", :aggregate_failures do
324
+ subject
325
+ expect { subject.save! }.to change(Listener, :count).by(2).
326
+ and change(Specialist, :count).by(1).
327
+ and change(CustomRule, :count).by(1)
328
+
329
+ expect(subject.title).to eq 'My Stage'
330
+ expect(subject.external_id).to be_nil
331
+ expect(subject.listeners.find_by(name: 'John')).to_not be_nil
332
+ expect(subject.listeners.find_by(name: 'Helen')).to_not be_nil
333
+ expect(subject.specialists.find_by(name: 'Jack')).to_not be_nil
334
+ expect(subject.custom_rules.first.description).to eq 'Kill all humans'
335
+ end
336
+ end
337
+
338
+ context 'polymorphic' do
339
+ let(:company) { Company.find_by(name: 'ABC Industries') }
340
+ let(:new_company) { company.amoeba_dup }
341
+
342
+ it 'does not fail with a deep inheritance' do
343
+ # employee = company.employees.where(name:'Joe').first
344
+ start_company_count = Company.count
345
+ start_customer_count = Customer.count
346
+ start_employee_count = Employee.count
347
+ start_address_count = Address.count
348
+ start_photo_count = Photo.count
349
+ new_company.name = "Copy of #{new_company.name}"
350
+ new_company.save
351
+ expect(Company.count).to eq(start_company_count + 1)
352
+ expect(Customer.count).to eq(start_customer_count + 1)
353
+ expect(Employee.count).to eq(start_employee_count + 1)
354
+ expect(Address.count).to eq(start_address_count + 4)
355
+ expect(Photo.count).to eq(start_photo_count + 2)
356
+
357
+ new_company.reload # fully reload from database
358
+ new_company_employees = new_company.employees
359
+ expect(new_company_employees.count).to eq(1)
360
+ new_company_employee_joe = new_company_employees.find_by(name: 'Joe')
361
+ expect(new_company_employee_joe.photos.count).to eq(1)
362
+ expect(new_company_employee_joe.photos.first.size).to eq(12_345)
363
+ expect(new_company_employee_joe.addresses.count).to eq(2)
364
+ expect(new_company_employee_joe.addresses.where(street: '123 My Street').count).to eq(1)
365
+ expect(new_company_employee_joe.addresses.where(street: '124 My Street').count).to eq(1)
366
+ new_company_customers = new_company.customers
367
+ expect(new_company_customers.count).to eq(1)
368
+ new_company_customer_my = new_company_customers.where(email: 'my@email.address').first
369
+ expect(new_company_customer_my.photos.count).to eq(1)
370
+ expect(new_company_customer_my.photos.first.size).to eq(54_321)
371
+ expect(new_company_customer_my.addresses.count).to eq(2)
372
+ expect(new_company_customer_my.addresses.where(street: '321 My Street').count).to eq(1)
373
+ expect(new_company_customer_my.addresses.where(street: '321 My Drive').count).to eq(1)
374
+ end
375
+ end
281
376
  end