Permalink
Browse files

Merge pull request #9529 from wangjohn/find_on_inverse_of_bugfix_9470

Find() on an association with an inverse will now scan existing in-memory records
  • Loading branch information...
2 parents 67a2c73 + 840ca09 commit 0fe4ae93b4f902ac5757304e015c415bf986a0d0 @jeremy jeremy committed Mar 19, 2013
View
@@ -1,5 +1,15 @@
## Rails 4.0.0 (unreleased) ##
+* If inverse_of is true on an association, then when one calls +find()+ on
+ the association, ActiveRecord will first look through the in-memory objects
+ in the association for a particular id. Then, it will go to the DB if it
+ is not found. This is accomplished by calling +find_by_scan+ in
+ collection associations whenever +options[:inverse_of]+ is not nil.
+
+ Fixes #9470.
+
+ *John Wang*
+
* `rake db:create` does not change permissions of the MySQL root user.
Fixes #8079.
@@ -79,7 +79,7 @@ def find(*args)
if block_given?
load_target.find(*args) { |*block_args| yield(*block_args) }
else
- if options[:finder_sql]
+ if options[:finder_sql] || options[:inverse_of]
find_by_scan(*args)
else
scope.find(*args)
@@ -567,7 +567,8 @@ def include_in_memory?(record)
end
end
- # If using a custom finder_sql, #find scans the entire collection.
+ # If using a custom finder_sql or if the :inverse_of option has been
+ # specified, then #find scans the entire collection.
def find_by_scan(*args)
expects_array = args.first.kind_of?(Array)
ids = args.flatten.compact.map{ |arg| arg.to_i }.uniq
@@ -278,6 +278,31 @@ def test_parent_instance_should_be_shared_with_first_n_and_last_n_children
assert interests[1].man.equal? man
end
+ def test_parent_instance_should_find_child_instance_using_child_instance_id
+ man = Man.create!
+ interest = Interest.create!
+ man.interests = [interest]
+
+ assert interest.equal?(man.interests.first), "The inverse association should use the interest already created and held in memory"
+ assert interest.equal?(man.interests.find(interest.id)), "The inverse association should use the interest already created and held in memory"
+ assert man.equal?(man.interests.first.man), "Two inversion should lead back to the same object that was originally held"
+ assert man.equal?(man.interests.find(interest.id).man), "Two inversions should lead back to the same object that was originally held"
+ end
+
+ def test_parent_instance_should_find_child_instance_using_child_instance_id_when_created
+ man = Man.create!
+ interest = Interest.create!(man: man)
+
+ assert man.equal?(man.interests.first.man), "Two inverses should lead back to the same object that was originally held"
+ assert man.equal?(man.interests.find(interest.id).man), "Two inversions should lead back to the same object that was originally held"
+
+ assert_equal man.name, man.interests.find(interest.id).man.name, "The name of the man should match before the name is changed"
+ man.name = "Ben Bitdiddle"
+ assert_equal man.name, man.interests.find(interest.id).man.name, "The name of the man should match after the parent name is changed"
+ man.interests.find(interest.id).man.name = "Alyssa P. Hacker"
+ assert_equal man.name, man.interests.find(interest.id).man.name, "The name of the man should match after the child name is changed"
+ end
+
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
assert_raise(ActiveRecord::InverseOfAssociationNotFoundError) { Man.first.secret_interests }
end

0 comments on commit 0fe4ae9

Please sign in to comment.