Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Has Many + non default primary key loads incorrect data

#1809

Has Many + non default primary key loads incorrect data.

I assume this is probably also the case for other has_* relationships, but have not verified.

I have a has_many association from class Foo to class Bar, where, for this specific relationship, the primary key on Foo is not id, nor is the foreign key on Bar id.


class Foo
  has_many, :bars, :primary_key => 'a_non_standard_key_name', :foreign_key => 'another_non_standard_key_name'
end

The relationship is one way, I have no need to navigate from Bar back to Foo, but only call a_foo.bars.

This works fine when working with a single object, but breaks down when you want to do eager association preloading to avoid n+1 query problem of loading bars for many foos.

When performing the following you find that


f = Foo.find :all, :include => :Bar
f.bars = [SOMETHING_UNEXPECTED]

The reason is that ActiveRecord creates the preloading query based on the default primary key of Foo (normally id).

It queries for Bar.another_non_standard_key_name matching Foo.id not Foo.a_non_standard_key_name

This causes seriously unexpected behaviour, and could easily go unnoticed since no errors are thrown.

I have found the hook in ActiveRecord where this functionality should be included and monkey patched for my system, because I need it now. I can't vouch for it's correctness, but we have many many specs for our product and none of them have broken because of this.

I'm running frozen rails 2.2.2

vendor/activerecord/lib/active_record/association_preload.rb, line 221

Change


primary_key_name = reflection.through_reflection_primary_key_name

to


primary_key_name = reflection.options[:primary_key] || reflection.through_reflection_primary_key_name

Hope this helps someone!

Emma

Reported by Emma Persky · January 28th, 2009 @ 08:07 PM

State: resolved
Milestone: 2.x
Assigned to: Frederick Cheung Frederick Cheung
Importance: none

Activity

  1. Pratik
    Pratik
    • Assigned user set to Frederick Cheung

    January 28th, 2009 @ 08:27 PM

  2. Emma Persky
    Emma Persky

    Ah, just checkout the rails git repo, and it looks like this has already been fixed.

    Thanks :)

    January 29th, 2009 @ 11:16 AM

  3. Frederick Cheung
    Frederick Cheung
    • State changed from new to resolved

    May 10th, 2009 @ 03:53 PM

  4. grosser
    grosser

    Still broken in 2.3.5:

    class Product < ActiveRecord::Base
      ...
      belongs_to :shop, :primary_key => :user_id, :foreign_key => :user_id
    end


    Product.first(:include=>:shop)
    results in:
    SELECT * FROM products  LIMIT 1
    SELECT * FROM shops WHERE (shops.id = 13008)
    

    but should be:

    SELECT * FROM products  LIMIT 1
    SELECT * FROM shops WHERE (shops.user_id = 13008)
    

    May 18th, 2010 @ 10:30 AM

  5. Neeraj Singh
    Neeraj Singh

    Just want to add that it is not an issue in rails3 edge.

    May 18th, 2010 @ 11:47 AM