@@ -114,21 +114,13 @@ def create!(attributes = {}, options = {}, &block)
114
114
# Add +records+ to this association. Returns +self+ so method calls may be chained.
115
115
# Since << flattens its argument list and inserts each record, +push+ and +concat+ behave identically.
116
116
def concat ( *records )
117
- result = true
118
117
load_target if owner . new_record?
119
118
120
- block = lambda do
121
- records . flatten . each do |record |
122
- raise_on_type_mismatch ( record )
123
- add_to_target ( record ) do |r |
124
- result &&= insert_record ( record ) unless owner . new_record?
125
- end
126
- end
119
+ if owner . new_record?
120
+ concat_records ( records )
121
+ else
122
+ transaction { concat_records ( records ) }
127
123
end
128
-
129
- owner . new_record? ? block . call : transaction ( &block )
130
-
131
- result && records
132
124
end
133
125
134
126
# Starts a transaction in the association class's database connection.
@@ -297,17 +289,11 @@ def replace(other_array)
297
289
other_array . each { |val | raise_on_type_mismatch ( val ) }
298
290
original_target = load_target . dup
299
291
300
- block = lambda do
301
- delete ( target - other_array )
302
-
303
- unless concat ( other_array - target )
304
- @target = original_target
305
- raise RecordNotSaved , "Failed to replace #{ reflection . name } because one or more of the " \
306
- "new records could not be saved."
307
- end
292
+ if owner . new_record?
293
+ replace_records ( other_array , original_target )
294
+ else
295
+ transaction { replace_records ( other_array , original_target ) }
308
296
end
309
-
310
- owner . new_record? ? block . call : transaction ( &block )
311
297
end
312
298
313
299
def include? ( record )
@@ -448,16 +434,20 @@ def delete_or_destroy(records, method)
448
434
records . each { |record | raise_on_type_mismatch ( record ) }
449
435
existing_records = records . reject { |r | r . new_record? }
450
436
451
- block = lambda do
452
- records . each { |record | callback ( :before_remove , record ) }
437
+ if existing_records . empty?
438
+ remove_records ( existing_records , records , method )
439
+ else
440
+ transaction { remove_records ( existing_records , records , method ) }
441
+ end
442
+ end
453
443
454
- delete_records ( existing_records , method ) if existing_records . any?
455
- records . each { |record | target . delete ( record ) }
444
+ def remove_records ( existing_records , records , method )
445
+ records . each { |record | callback ( :before_remove , record ) }
456
446
457
- records . each { | record | callback ( :after_remove , record ) }
458
- end
447
+ delete_records ( existing_records , method ) if existing_records . any?
448
+ records . each { | record | target . delete ( record ) }
459
449
460
- existing_records . any? ? transaction ( & block ) : block . call
450
+ records . each { | record | callback ( :after_remove , record ) }
461
451
end
462
452
463
453
# Delete the given records from the association, using one of the methods :destroy,
@@ -466,6 +456,29 @@ def delete_records(records, method)
466
456
raise NotImplementedError
467
457
end
468
458
459
+ def replace_records ( new_target , original_target )
460
+ delete ( target - new_target )
461
+
462
+ unless concat ( new_target - target )
463
+ @target = original_target
464
+ raise RecordNotSaved , "Failed to replace #{ reflection . name } because one or more of the " \
465
+ "new records could not be saved."
466
+ end
467
+ end
468
+
469
+ def concat_records ( records )
470
+ result = true
471
+
472
+ records . flatten . each do |record |
473
+ raise_on_type_mismatch ( record )
474
+ add_to_target ( record ) do |r |
475
+ result &&= insert_record ( record ) unless owner . new_record?
476
+ end
477
+ end
478
+
479
+ result && records
480
+ end
481
+
469
482
def callback ( method , record )
470
483
callbacks_for ( method ) . each do |callback |
471
484
case callback
0 commit comments