@@ -221,8 +221,10 @@ def define_autosave_validation_callbacks(reflection)
221
221
if reflection . validate? && !method_defined? ( validation_method )
222
222
if reflection . collection?
223
223
method = :validate_collection_association
224
+ elsif reflection . has_one?
225
+ method = :validate_has_one_association
224
226
else
225
- method = :validate_single_association
227
+ method = :validate_belongs_to_association
226
228
end
227
229
228
230
define_non_cyclic_method ( validation_method ) { send ( method , reflection ) }
@@ -274,6 +276,16 @@ def changed_for_autosave?
274
276
new_record? || has_changes_to_save? || marked_for_destruction? || nested_records_changed_for_autosave?
275
277
end
276
278
279
+ def validating_belongs_to_for? ( association )
280
+ @validating_belongs_to_for ||= { }
281
+ @validating_belongs_to_for [ association ]
282
+ end
283
+
284
+ def autosaving_belongs_to_for? ( association )
285
+ @autosaving_belongs_to_for ||= { }
286
+ @autosaving_belongs_to_for [ association ]
287
+ end
288
+
277
289
private
278
290
def init_internals
279
291
super
@@ -313,18 +325,35 @@ def nested_records_changed_for_autosave?
313
325
end
314
326
315
327
# Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
316
- # turned on for the association.
317
- def validate_single_association ( reflection )
328
+ # turned on for the has_one association.
329
+ def validate_has_one_association ( reflection )
318
330
association = association_instance_get ( reflection . name )
319
331
record = association && association . reader
320
332
return unless record && ( record . changed_for_autosave? || custom_validation_context? )
321
333
322
- inverse_belongs_to_association = inverse_belongs_to_association_for ( reflection , record )
323
- return if inverse_belongs_to_association && inverse_belongs_to_association . updated?
334
+ inverse_association = reflection . inverse_of && record . association ( reflection . inverse_of . name )
335
+ return if inverse_association && ( record . validating_belongs_to_for? ( inverse_association ) ||
336
+ record . autosaving_belongs_to_for? ( inverse_association ) )
324
337
325
338
association_valid? ( association , record )
326
339
end
327
340
341
+ # Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
342
+ # turned on for the belongs_to association.
343
+ def validate_belongs_to_association ( reflection )
344
+ association = association_instance_get ( reflection . name )
345
+ record = association && association . reader
346
+ return unless record && ( record . changed_for_autosave? || custom_validation_context? )
347
+
348
+ begin
349
+ @validating_belongs_to_for ||= { }
350
+ @validating_belongs_to_for [ association ] = true
351
+ association_valid? ( association , record )
352
+ ensure
353
+ @validating_belongs_to_for [ association ] = false
354
+ end
355
+ end
356
+
328
357
# Validate the associated records if <tt>:validate</tt> or
329
358
# <tt>:autosave</tt> is turned on for the association specified by
330
359
# +reflection+.
@@ -443,13 +472,7 @@ def save_has_one_association(reflection)
443
472
elsif autosave != false
444
473
primary_key = Array ( compute_primary_key ( reflection , self ) ) . map ( &:to_s )
445
474
primary_key_value = primary_key . map { |key | _read_attribute ( key ) }
446
-
447
- return unless ( autosave && record . changed_for_autosave? ) || ( record_changed = _record_changed? ( reflection , record , primary_key_value ) )
448
-
449
- unless record_changed
450
- inverse_belongs_to_association = inverse_belongs_to_association_for ( reflection , record )
451
- return if inverse_belongs_to_association && inverse_belongs_to_association . updated?
452
- end
475
+ return unless ( autosave && record . changed_for_autosave? ) || _record_changed? ( reflection , record , primary_key_value )
453
476
454
477
unless reflection . through_reflection
455
478
foreign_key = Array ( reflection . foreign_key )
@@ -462,19 +485,15 @@ def save_has_one_association(reflection)
462
485
association . set_inverse_instance ( record )
463
486
end
464
487
488
+ inverse_association = reflection . inverse_of && record . association ( reflection . inverse_of . name )
489
+ return if inverse_association && record . autosaving_belongs_to_for? ( inverse_association )
490
+
465
491
saved = record . save ( validate : !autosave )
466
492
raise ActiveRecord ::Rollback if !saved && autosave
467
493
saved
468
494
end
469
495
end
470
496
471
- def inverse_belongs_to_association_for ( reflection , record )
472
- !reflection . belongs_to? &&
473
- reflection . inverse_of &&
474
- reflection . inverse_of . belongs_to? &&
475
- record . association ( reflection . inverse_of . name )
476
- end
477
-
478
497
# If the record is new or it has changed, returns true.
479
498
def _record_changed? ( reflection , record , key )
480
499
record . new_record? ||
@@ -515,7 +534,15 @@ def save_belongs_to_association(reflection)
515
534
foreign_key . each { |key | self [ key ] = nil }
516
535
record . destroy
517
536
elsif autosave != false
518
- saved = record . save ( validate : !autosave ) if record . new_record? || ( autosave && record . changed_for_autosave? )
537
+ saved = if record . new_record? || ( autosave && record . changed_for_autosave? )
538
+ begin
539
+ @autosaving_belongs_to_for ||= { }
540
+ @autosaving_belongs_to_for [ association ] = true
541
+ record . save ( validate : !autosave )
542
+ ensure
543
+ @autosaving_belongs_to_for [ association ] = false
544
+ end
545
+ end
519
546
520
547
if association . updated?
521
548
primary_key = Array ( compute_primary_key ( reflection , record ) ) . map ( &:to_s )
0 commit comments