Forum: Ruby on Rails has_many, through, and custom primary keys

Announcement (2017-05-07): is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see and for other Rails- und Ruby-related community platforms.
1b70bc7deb2bfa77214558fb1178ecff?d=identicon&s=25 Fyodor Golos (fedot)
on 2007-02-16 21:00
When attempting to use a "has_many :through" association with three
models using non-standard primary keys, Rails is not constructing SQL
finder query properly. For some reason it is not using correct primary
key column for the "middle" table. Here is a detailed example:

create_table :books, :primary_key => :my_book_id, :force => true do |t|
  t.column :name, :string

create_table :chapters, :primary_key => :my_chapter_id, :force => true
do |t|
  t.column :parent_book_id, :integer
  t.column :name, :string

create_table :paragraphs, :primary_key => :paragraph_id, :force => true
do |t|
  t.column :parent_chapter_id, :integer
  t.column :name, :string

class Book < ActiveRecord::Base
  has_many :chapters, :foreign_key => :parent_book_id
  has_many :paragraphs, :through => :chapters, :source => :paragraphs

class Chapter < ActiveRecord::Base
  has_many :paragraphs, :foreign_key => :parent_chapter_id
  belongs_to :book, :foreign_key => :parent_book_id

class Paragraph < ActiveRecord::Base
  belongs_to :chapter, :foreign_key => :parent_chapter_id

Now, when I run the following from the console:


The following SQL gets sent to MySQL:

SELECT paragraphs.* FROM paragraphs INNER JOIN chapters ON
paragraphs.parent_chapter_id = chapters.my_paragraph_id WHERE
chapters.parent_book_id = 1

The ON clause is in error. Instead of saying:

ON paragraphs.parent_chapter_id = chapters.my_paragraph_id

it should be:

ON paragraphs.parent_chapter_id = chapters.my_chapter_id

Am I missing some option in one of my associations? Or am I hitting a
Rails bug?

BTW, I am running Rails 1.2.1

Thanks in advance,
Fyodor Golos
1b70bc7deb2bfa77214558fb1178ecff?d=identicon&s=25 Fyodor Golos (fedot)
on 2007-02-16 22:33
I checked out and
started digging into this problem...

def construct_joins(custom_joins = nil)
  polymorphic_join = nil
  if @reflection.through_reflection.options[:as] ||
@reflection.source_reflection.macro == :belongs_to
    reflection_primary_key = @reflection.klass.primary_key
    source_primary_key     =
    reflection_primary_key =
    source_primary_key     = @reflection.klass.primary_key
    if @reflection.source_reflection.options[:as]
      polymorphic_join = "AND %s.%s = %s" % [
  "INNER JOIN %s ON %s.%s = %s.%s %s #{@reflection.options[:joins]}
#{custom_joins}" % [
    @reflection.table_name, reflection_primary_key,
    @reflection.through_reflection.table_name, source_primary_key,

Skipping down to line 181:

source_primary_key = @reflection.klass.primary_key

Unless I am totally mistaken, it should have read like this:

source_primary_key = @reflection.through_reflection.klass.primary_key

Making that change does not break any Rails tests (which probably
doesn't mean much, since Rails tests are probably not using non-standard
primary key column names) and fixes my problem by constructing correct
SQL statement.

It is quite possible that line 177 also needs to be modified in a
similar manner to read:

reflection_primary_key =

Can someone more knowledgeable confirm this before I make and submit a

Thank you,
Fyodor Golos
This topic is locked and can not be replied to.