This project is archived and is in readonly mode.

#2068 ✓invalid
Jaime Bellmyer

HABTM Relationships Fail When Join Table has Primary Key

Reported by Jaime Bellmyer | February 25th, 2009 @ 06:49 AM | in 2.x

has_and_belongs_to_many relationships fail in an unexpected way when the join table has a primary key with the same name as a column in the associated table. The most common example is when the join table is created by migration without including the :id => false option, like so:


  create_table :developers_projects do |t|
    t.integer :developer_id
    t.integer :project_id
  end

The results are problematic. ActiveRecord takes any non-foreign-key columns in the join table, and fills them with values from the associated table. Therefore, ActiveRecord tries to forcibly assign the id of the join record to be the same as the id of the associated table. That's why, in the example above, you can only add a project to one developer.

My included patch excludes the join table primary key from being overridden, if it exists. It also includes the relevant test in has_and_belongs_to_many_associations_test.rb, called test_adding_a_collection_when_join_table_has_primary_key.

The result is that habtm join tables work as expected. Some may make the argument that join tables shouldn't have primary keys. While it's true join tables almost never need them, they shouldn't become a liability that appears only after you've added several records.

Comments and changes to this ticket

  • Jaime Bellmyer

    Jaime Bellmyer February 25th, 2009 @ 05:15 PM

    • Tag changed from activerecord, duplicate, has_and_belongs_to_many, join_table, primary_key to activerecord, duplicate, has_and_belongs_to_many, join_table, patch, primary_key

    After re-reading the ActiveRecord::Associations::ClassMethods docs, a new solution comes to mind. We're telling people in the docs not to have a primary key on the join table. Maybe instead of allowing primary keys to work error-free, we should raise an exception when the association is first made. This way having a primary key in your join table will fail right away, fail loudly, and with an error message that can be easily understood/researched.

    If this is the better way to go, I can certainly implement it. Feedback is greatly appreciated.

  • Jaime Bellmyer

    Jaime Bellmyer February 26th, 2009 @ 04:54 PM

    Can somebody with permissions please kill this ticket? I recently learned that this solution is not what the rails community wants. It's based on the legacy use of habtm before has_many :through came around. Now the use of habtm join tables is deprecated for anything fancy.

    Still, we still have the problem of cryptic failure when the habtm join table contains a primary key. So I've created a different solution in ticket #2086 that raises an exception with a clear explanation.

  • Pratik

    Pratik March 9th, 2009 @ 01:34 PM

    • Assigned user set to “Pratik”
    • State changed from “new” to “invalid”
    • Title changed from “[PATCH] HABTM Relationships Fail When Join Table has Primary Key” to “HABTM Relationships Fail When Join Table has Primary Key”
  • Reto

    Reto July 16th, 2009 @ 10:25 AM

    Sorry for waking up this old ticket, but I almost shoot my foot due to this problem today.

    In my opinion the documentation doesn't stress this problem enough, it says:
    'The join table should not have a primary key or a model associated with it. You must manually generate the join table with a migration such as this:'[0]

    this even suggests that it is possible (technically), but one 'should not' use a primary key. But it is not possible and it reveals this ugly bug.

    Would it possible to add a clear note about that problem in the documentation?

    [0] http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassM...

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

Referenced by

Pages