Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Set inverse associations when using scopes

Currently using scopes through a has_many association will not set
the inverse association, e.g:

  product = Product.first
  product.variants.enabled.first.product.equal? product
  => false

This commit fixes it by copying the association into the scope and
then attempting to set the inverse association when the records are
loaded.
  • Loading branch information...
commit 9f607fb4ddb3789b0859e05bf7810354a867bfc2 1 parent ea84b0c
@pixeltrix pixeltrix authored
View
1  activerecord/lib/active_record/associations/association_scope.rb
@@ -15,6 +15,7 @@ def initialize(association)
def scope
scope = klass.unscoped
+ scope.association = @association
scope.merge! eval_scope(klass, reflection.scope) if reflection.scope
add_constraints(scope)
end
View
4 activerecord/lib/active_record/associations/collection_proxy.rb
@@ -35,8 +35,8 @@ module Associations
# instantiation of the actual post records.
class CollectionProxy < Relation
def initialize(association) #:nodoc:
- @association = association
super association.klass, association.klass.arel_table
+ @association = association
merge! association.scope
end
@@ -896,7 +896,7 @@ def ==(other)
end
# Returns a new array of objects from the collection. If the collection
- # hasn't been loaded, it fetches the records from the database.
+ # hasn't been loaded, it fetches the records from the database.
#
# class Person < ActiveRecord::Base
# has_many :pets
View
7 activerecord/lib/active_record/relation.rb
@@ -17,7 +17,7 @@ class Relation
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
attr_reader :table, :klass, :loaded
- attr_accessor :default_scoped
+ attr_accessor :default_scoped, :association
alias :model :klass
alias :loaded? :loaded
alias :default_scoped? :default_scoped
@@ -29,6 +29,7 @@ def initialize(klass, table, values = {})
@implicit_readonly = nil
@loaded = false
@default_scoped = false
+ @association = nil
end
def insert(values)
@@ -572,6 +573,10 @@ def exec_queries
@records = default_scoped.to_a
end
+ if association
+ @records.each { |record| association.set_inverse_instance(record) }
+ end
+
@loaded = true
@records
end
View
4 activerecord/lib/active_record/relation/merger.rb
@@ -35,6 +35,10 @@ def initialize(relation, other)
other = other.with_default_scope
end
+ if other.association
+ relation.association = other.association
+ end
+
@relation = relation
@values = other.values
end
View
20 activerecord/test/cases/associations/inverse_associations_test.rb
@@ -261,8 +261,24 @@ def test_parent_instance_should_be_shared_with_replaced_via_accessor_children
def test_parent_instance_should_be_shared_with_first_and_last_child
man = Man.first
- assert man.interests.first.man.equal? man
- assert man.interests.last.man.equal? man
+ assert man.interests.first.man.equal?(man), "Man should be the same instance when using association.first"
+ assert man.interests.last.man.equal?(man), "Man should be the same instance when using association.last"
+ end
+
+ def test_parent_instance_should_be_shared_with_all_children
+ man = Man.first
+ assert man.interests.to_a.all?{ |interest| interest.man.equal?(man) }, "Man should be the same instance when using association.to_a"
+ end
+
+ def test_parent_instance_should_be_shared_with_first_and_last_child_when_using_scope
+ man = Man.first
+ assert man.interests.by_topic.first.man.equal?(man), "Man should be the same instance when using association.scope.first"
+ assert man.interests.by_topic.last.man.equal?(man), "Man should be the same instance when using association.scope.last"
+ end
+
+ def test_parent_instance_should_be_shared_with_all_children_when_using_scope
+ man = Man.first
+ assert man.interests.by_topic.to_a.all?{ |interest| interest.man.equal?(man) }, "Man should be the same instance when using association.scope.to_a"
end
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
View
4 activerecord/test/models/interest.rb
@@ -2,4 +2,8 @@ class Interest < ActiveRecord::Base
belongs_to :man, :inverse_of => :interests
belongs_to :polymorphic_man, :polymorphic => true, :inverse_of => :polymorphic_interests
belongs_to :zine, :inverse_of => :interests
+
+ def self.by_topic
+ order(arel_table[:topic])
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.