diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index 1109fee462..c8716741b0 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -16,19 +16,6 @@ module ActiveRecord end end - def replace(record) - if record - raise_on_type_mismatch!(record) - update_counters_on_replace(record) - set_inverse_instance(record) - @updated = true - else - decrement_counters - end - - self.target = record - end - def target=(record) replace_keys(record) super @@ -56,6 +43,18 @@ module ActiveRecord end private + def replace(record) + if record + raise_on_type_mismatch!(record) + update_counters_on_replace(record) + set_inverse_instance(record) + @updated = true + else + decrement_counters + end + + self.target = record + end def update_counters(by) if require_counter_update? && foreign_key_present? diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 4e8e7ee43b..d211884135 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -23,35 +23,6 @@ module ActiveRecord end end - def replace(record, save = true) - raise_on_type_mismatch!(record) if record - load_target - - return target unless target || record - - assigning_another_record = target != record - if assigning_another_record || record.has_changes_to_save? - save &&= owner.persisted? - - transaction_if(save) do - remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record - - if record - set_owner_attributes(record) - set_inverse_instance(record) - - if save && !record.save - nullify_owner_attributes(record) - set_owner_attributes(target) if target - raise RecordNotSaved, "Failed to save the new associated #{reflection.name}." - end - end - end - end - - self.target = record - end - def delete(method = options[:dependent]) if load_target case method @@ -68,6 +39,33 @@ module ActiveRecord end private + def replace(record, save = true) + raise_on_type_mismatch!(record) if record + + return target unless load_target || record + + assigning_another_record = target != record + if assigning_another_record || record.has_changes_to_save? + save &&= owner.persisted? + + transaction_if(save) do + remove_target!(options[:dependent]) if target && !target.destroyed? && assigning_another_record + + if record + set_owner_attributes(record) + set_inverse_instance(record) + + if save && !record.save + nullify_owner_attributes(record) + set_owner_attributes(target) if target + raise RecordNotSaved, "Failed to save the new associated #{reflection.name}." + end + end + end + end + + self.target = record + end # The reason that the save param for replace is false, if for create (not just build), # is because the setting of the foreign keys is actually handled by the scoping when diff --git a/activerecord/lib/active_record/associations/has_one_through_association.rb b/activerecord/lib/active_record/associations/has_one_through_association.rb index 019bf0729f..10978b2d93 100644 --- a/activerecord/lib/active_record/associations/has_one_through_association.rb +++ b/activerecord/lib/active_record/associations/has_one_through_association.rb @@ -6,12 +6,12 @@ module ActiveRecord class HasOneThroughAssociation < HasOneAssociation #:nodoc: include ThroughAssociation - def replace(record, save = true) - create_through_record(record, save) - self.target = record - end - private + def replace(record, save = true) + create_through_record(record, save) + self.target = record + end + def create_through_record(record, save) ensure_not_nested