# Has\_many, through, and custom primary keys

**URL:** <https://www.ruby-forum.com/t/has-many-through-and-custom-primary-keys/85858>\
**Category:** Rails\
**Created:** [February 16, 2007, 9:00pm UTC](https://www.ruby-forum.com/t/has-many-through-and-custom-primary-keys/85858 "2007-02-16T21:00:00Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![fedot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/82dd89/32.png) [@fedot](https://www.ruby-forum.com/u/fedot)\
**Post date:** [February 16, 2007, 9:00pm UTC](https://www.ruby-forum.com/t/has-many-through-and-custom-primary-keys/85858/1 "2007-02-16T21:00:00Z")

</div>

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  
end

create\_table :chapters, :primary\_key =\> :my\_chapter\_id, :force =\> true  
do |t|  
t.column :parent\_book\_id, :integer  
t.column :name, :string  
end

create\_table :paragraphs, :primary\_key =\> :paragraph\_id, :force =\> true  
do |t|  
t.column :parent\_chapter\_id, :integer  
t.column :name, :string  
end

class Book \< ActiveRecord::Base  
set\_primary\_key(:my\_book\_id)  
has\_many :chapters, :foreign\_key =\> :parent\_book\_id  
has\_many :paragraphs, :through =\> :chapters, :source =\> :paragraphs  
end

class Chapter \< ActiveRecord::Base  
set\_primary\_key(:my\_chapter\_id)  
has\_many :paragraphs, :foreign\_key =\> :parent\_chapter\_id  
belongs\_to :book, :foreign\_key =\> :parent\_book\_id  
end

class Paragraph \< ActiveRecord::Base  
set\_primary\_key(:my\_paragraph\_id)  
belongs\_to :chapter, :foreign\_key =\> :parent\_chapter\_id  
end

Now, when I run the following from the console:

Book.find(1).paragraphs

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

---

<div class="post-metadata">

**Author:** ![fedot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/f/82dd89/32.png) [@fedot](https://www.ruby-forum.com/u/fedot)\
**Post date:** [February 16, 2007, 10:33pm UTC](https://www.ruby-forum.com/t/has-many-through-and-custom-primary-keys/85858/2 "2007-02-16T22:33:49Z")

</div>

I checked out [http://dev.rubyonrails.org/svn/rails/tags/rel\_1-2-1](http://dev.rubyonrails.org/svn/rails/tags/rel_1-2-1) 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.source\_reflection.primary\_key\_name  
else  
reflection\_primary\_key =  
@reflection.source\_reflection.primary\_key\_name  
source\_primary\_key = @reflection.klass.primary\_key  
if @reflection.source\_reflection.options[:as]  
polymorphic\_join = “AND %s.%s = %s” % [  
@reflection.table\_name,  
“#{@reflection.source\_reflection.options[:as]}\_type”,  
@owner.class.quote\_value(@reflection.through\_reflection.klass.name)  
]  
end  
end  
“INNER JOIN %s ON %s.%s = %s.%s %s #{@reflection.options[:joins]}  
#{custom\_joins}” % [  
@reflection.through\_reflection.table\_name,  
@reflection.table\_name, reflection\_primary\_key,  
@reflection.through\_reflection.table\_name, source\_primary\_key,  
polymorphic\_join  
]  
end

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 =  
@reflection.through\_reflection.klass.primary\_key

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

Thank you,  
Fyodor Golos
