diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2018-05-02 06:35:25 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2018-05-25 23:57:09 +0900 |
commit | 6edf354b656ec556c3573402019504a519531953 (patch) | |
tree | d6d772aa578bd9594fc1e78fe610dcff86fb0a8b /activerecord/lib | |
parent | 8a600183550298a1f350a8fa8d72630da607fb60 (diff) | |
download | rails-6edf354b656ec556c3573402019504a519531953.tar.gz rails-6edf354b656ec556c3573402019504a519531953.tar.bz2 rails-6edf354b656ec556c3573402019504a519531953.zip |
Eager loading won't mutate owner record
Since #31575, `BelongsToAssociation#target=` replaces owner record's
foreign key to fix an inverse association bug.
But the method is not only used for inverse association but also used
for eager loading/preloading, it caused some public behavior changes
(#32338, #32375).
To avoid any side-effect in loading associations, I reverted the
overriding `#target=`, then introduced `#inversed_from` to replace
foreign key in `set_inverse_instance`.
Closes #32375.
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/associations/association.rb | 26 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/belongs_to_association.rb | 4 |
2 files changed, 19 insertions, 11 deletions
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index ca8c7794e0..d2934c830a 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -19,7 +19,6 @@ module ActiveRecord # HasManyThroughAssociation + ThroughAssociation class Association #:nodoc: attr_reader :owner, :target, :reflection - attr_accessor :inversed delegate :options, to: :reflection @@ -67,7 +66,7 @@ module ActiveRecord # # Note that if the target has not been loaded, it is not considered stale. def stale_target? - !inversed && loaded? && @stale_state != stale_state + !@inversed && loaded? && @stale_state != stale_state end # Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+. @@ -98,23 +97,24 @@ module ActiveRecord # Set the inverse association, if possible def set_inverse_instance(record) - if invertible_for?(record) - inverse = record.association(inverse_reflection_for(record).name) - inverse.target = owner - inverse.inversed = true + if inverse = inverse_association_for(record) + inverse.inversed_from(owner) end record end # Remove the inverse association, if possible def remove_inverse_instance(record) - if invertible_for?(record) - inverse = record.association(inverse_reflection_for(record).name) - inverse.target = nil - inverse.inversed = false + if inverse = inverse_association_for(record) + inverse.inversed_from(nil) end end + def inversed_from(record) + self.target = record + @inversed = !!record + end + # Returns the class of the target. belongs_to polymorphic overrides this to look at the # polymorphic_type field on the owner. def klass @@ -240,6 +240,12 @@ module ActiveRecord end end + def inverse_association_for(record) + if invertible_for?(record) + record.association(inverse_reflection_for(record).name) + end + end + # Can be redefined by subclasses, notably polymorphic belongs_to # The record parameter is necessary to support polymorphic inverses as we must check for # the association in the specific class of the record. diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index c8716741b0..775559e224 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -16,7 +16,7 @@ module ActiveRecord end end - def target=(record) + def inversed_from(record) replace_keys(record) super end @@ -53,6 +53,8 @@ module ActiveRecord decrement_counters end + replace_keys(record) + self.target = record end |