This project is archived and is in readonly mode.

#2187 ✓invalid
Minh Tran

belongs to association eager/pre- load fails when foreign key is same as association name

Reported by Minh Tran | March 9th, 2009 @ 11:22 PM | in 2.x

There is a subtle bug in the association preload code that causes eager loading not to work when the foreign key name is the same as the association name. For example,


belongs_to :created_by, :class => 'Person', :foreign_key => 'created_by'

Attached is a diff with a test case that will reveal the problem, as well as a two-line fix for it. The problem exists in 2.2.2 and AFAIK, 2.3 as well.

To elaborate, the problem occurs in "association_preload.rb" in method preload_belongs_to_association(). The id/key is obtained by doing:


record.send(primary_key_name)

However, in the case where the association name is the same as the foreign key, this will return the associated object, not the numeric id. Accessing the key/id with [ ] (square brackets) instead of send() will fix the problem.

This issue does not seem to exist with the other associations because they use construct_id_map(), which accesses the numeric id with [] already.

In the attached patch, the test case I wrote is quite simple. If eager loading worked (i.e. find() with :include), then the number of generated queries should be small.

For your reference, the failure output for the test case without the two-line fix would be:


  1) Failure:
test_preload_belongs_to_with_foreign_key_name_same_as_association_name(EagerAssociationTest)
    [./test/cases/../../lib/active_record/test_case.rb:31:in `assert_queries'
     ./test/cases/associations/eager_test.rb:785:in `test_preload_belongs_to_with_foreign_key_name_same_as_association_name'
     ./test/cases/../../../activesupport/lib/active_support/testing/setup_and_teardown.rb:57:in `__send__'
     ./test/cases/../../../activesupport/lib/active_support/testing/setup_and_teardown.rb:57:in `run']:
4 instead of 2 queries were executed.
Queries:
SELECT * FROM `funny_jokes` WHERE (created_by IS NOT NULL)
SELECT * FROM `people` WHERE (`people`.`id` = 2)
SELECT * FROM `people` WHERE (`people`.`id` = 1)
SELECT * FROM `people` WHERE (`people`.`id` IN (0,0)) .
<2> expected but was
<4>.

2017 tests, 6552 assertions, 1 failures, 0 errors

Comments and changes to this ticket

  • David Trasbo

    David Trasbo April 15th, 2010 @ 08:04 PM

    • Assigned user set to “Ryan Bigg”

    Giving a column and an association the same name is bound to cause trouble. Rails doesn't and shouldn't try to support doing things like this. Rename the column created_by_id, e.g. This ticket can be marked as invalid.

  • David Trasbo

    David Trasbo April 15th, 2010 @ 08:04 PM

    Giving a column and an association the same name is bound to cause trouble. Rails doesn't and shouldn't try to support doing things like this. Rename the column created_by_id, e.g. This ticket can be marked as invalid.

  • Ryan Bigg

    Ryan Bigg April 15th, 2010 @ 10:26 PM

    • State changed from “new” to “invalid”

    Yup, never give your association the name of the foreign key, always give the foreign_key an _id suffix.

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

People watching this ticket

Attachments

Pages