Permalink
Browse files

Calling find() on an association with an inverse will now check to see

if the association already holds that record in memory before checking
the database for the specified ids.
  • Loading branch information...
1 parent a6c5ee3 commit 840ca09a1151fafe1cb3299f12437378d25f2ce5 @wangjohn wangjohn 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 840ca09

Please sign in to comment.