diff options
author | wangjohn <wangjohn@mit.edu> | 2013-03-19 16:33:49 -0400 |
---|---|---|
committer | wangjohn <wangjohn@mit.edu> | 2013-03-19 16:33:49 -0400 |
commit | 840ca09a1151fafe1cb3299f12437378d25f2ce5 (patch) | |
tree | 95b740f525c3303b5b5938f4dd58dffdd8fa05fa /activerecord | |
parent | a6c5ee3032c50720760f7a4c895206b4205836c0 (diff) | |
download | rails-840ca09a1151fafe1cb3299f12437378d25f2ce5.tar.gz rails-840ca09a1151fafe1cb3299f12437378d25f2ce5.tar.bz2 rails-840ca09a1151fafe1cb3299f12437378d25f2ce5.zip |
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.
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/CHANGELOG.md | 10 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/collection_association.rb | 5 | ||||
-rw-r--r-- | activerecord/test/cases/associations/inverse_associations_test.rb | 25 |
3 files changed, 38 insertions, 2 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index e5ab6bac58..79247e3028 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -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. diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 906560bd44..73b4a187c8 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -79,7 +79,7 @@ module ActiveRecord 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 @@ module ActiveRecord 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 diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index 8c9b4fb921..c8cad84013 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -278,6 +278,31 @@ class InverseHasManyTests < ActiveRecord::TestCase 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 |