Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #6779 (closed defect: invalid)

Opened 3 years ago

Last modified 3 years ago

HABTM - primary key column "id" of join table is being set to the joined table's id when adding a new relation via "model.associations.push associated_model" [PATCH]

Reported by: timcharper Assigned to: david
Priority: normal Milestone: 1.2
Component: ActiveRecord Version: 1.2.0rc1
Severity: major Keywords: habtm activerecord
Cc: minam

Description

I have a self-referential join table, named tranzactions

  create_table "tranzactions", :force => true do |t|
    t.column "tranzaction_type",  :string,  :limit => 25
    t.column "category_id",       :integer
    t.column "created_on",        :date
    t.column "due_on",            :date
    t.column "account",           :string,  :limit => 50
    t.column "amount",            :float
    t.column "notes",             :text
  end

I also have has_and_belongs_to_many join table like the following:

  create_table "tranzaction_relations", :force => true do |t|
    t.column "invoice_id", :integer
    t.column "payment_id", :integer
  end

My habtm join is defined as follows:

  # relationships to help access related payments/invoices
  has_and_belongs_to_many :invoices,
      :class_name => 'Tranzaction',
      :join_table => 'tranzaction_relations',
      :foreign_key => 'payment_id',
      :association_foreign_key => 'invoice_id'

  has_and_belongs_to_many :payments,
      :class_name => 'Tranzaction',
      :join_table => 'tranzaction_relations',
      :foreign_key => 'invoice_id',
      :association_foreign_key => 'payment_id'
  

When I do an operation like: tranzaction=Tranzaction.find(1) tranzaction.invoices.push(Tranzaction.find(2))

this query is executed:

INSERT INTO tranzaction_relations (`invoice_id`, `id`, `payment_id`) VALUES (1, 2, 2)

Then, I execute this: tranzaction=Tranzaction.find(3) tranzaction.invoices.push(Tranzaction.find(2))

this query is executed:

INSERT INTO tranzaction_relations (`invoice_id`, `id`, `payment_id`) VALUES (3, 2, 2)

However, since "id" is a primary key, an error is thrown because it's a duplicate.

The error is that the "id" field shouldn't be being copied. It's occuring here:

Index: C:/www/rails/trunk/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
===================================================================
--- C:/www/rails/trunk/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb	(revision 5699)
+++ C:/www/rails/trunk/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb	(working copy)
@@ -106,11 +106,6 @@
                   attributes[column.name] = @owner.quoted_id
                 when @reflection.association_foreign_key
                   attributes[column.name] = record.quoted_id
-                else
-                  if record.attributes.has_key?(column.name)
-                    value = @owner.send(:quote_value, record[column.name], column)
-                    attributes[column.name] = value unless value.nil?
-                  end
               end
               attributes
             end

(where the - signs are) The code reads all columns from my join table, [ "id", "invoice_id", "payment_id" ]. Then, it seeks to fill those values. The above marked piece of code sees the "id" field, doesn't know what to do with it, so it just copies another tables value.

Why is this behaving this way? If you apply the posted patch, it fixes the problem. But I don't know what that code is for... it may be important. David? Minam? You guys touched it last? Any idea what it's about?

Thanks,

Tim

(contact me directly tim, att lunawebs, dot com}

Change History

(in reply to: ↑ description ) 12/07/06 00:43:41 changed by timcharper

The patch I posted does in fact have serious consequences. Though the problem was fixed, now when I push tranzaction.invoices.push(invoice) invoice.id is set to the tranzaction_relations.id for the join.

I suppose what we'll need to do is detect the primary key column, and not touch it. the data returned by @owner.connection.columns(@reflection.options[:join_table], "#{@reflection.options[:join_table]} Columns") returns an entry for "primary key", but doesn't appear to be populated. What solutions could there be for this?

Tim

12/07/06 06:56:24 changed by hasmanyjosh

  • status changed from new to closed.
  • resolution set to invalid.

This is not a bug, and the behavior is as expected. A HABTM join table should not have a primary key. If you want that functionality, use has_many :through. A bit of searching would have found other tickets on this matter - #5141 and #5216 for example.