From 86187f8128d9f0cf892368dc0efdf8f5554baa90 Mon Sep 17 00:00:00 2001 From: Tom Lea Date: Wed, 22 Oct 2008 23:29:52 +0100 Subject: [PATCH] Self referential HABTM associations should not be allowed to be created unless the association_foreign_key has been manually assigned. If this is not prevented, we end up with an join table which has only one column, which is referenced twice... causing odd results. This patch causes trying to do this to fail fast, saving on debug time. --- activerecord/lib/active_record/associations.rb | 10 ++++++++++ .../has_and_belongs_to_many_associations_test.rb | 8 ++++++++ 2 files changed, 18 insertions(+), 0 deletions(-) diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 52f6a04..f911d21 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -61,6 +61,12 @@ module ActiveRecord end end + class HasAndBelongsToManyAssociationForeignKeyNeeded < ActiveRecordError #:nodoc: + def initialize(reflection) + super("Cannot create self referential has_and_belongs_to_many association on '#{reflection.class_name rescue nil}##{reflection.name rescue nil}'. :association_foreign_key cannot be the same as the :foreign_key.") + end + end + class EagerLoadPolymorphicError < ActiveRecordError #:nodoc: def initialize(reflection) super("Can not eagerly load the polymorphic association #{reflection.name.inspect}") @@ -1610,6 +1616,10 @@ module ActiveRecord options[:extend] = create_extension_modules(association_id, extension, options[:extend]) reflection = create_reflection(:has_and_belongs_to_many, association_id, options, self) + + if reflection.association_foreign_key == reflection.primary_key_name + raise HasAndBelongsToManyAssociationForeignKeyNeeded.new(reflection) + end reflection.options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(reflection.class_name)) diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb index 2949f1d..400e115 100644 --- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb @@ -738,6 +738,14 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase # Array#count in Ruby >=1.8.7, which would raise an ArgumentError assert_nothing_raised { david.projects.count(:all, :conditions => '1=1') } end + + def test_self_referential_habtm_without_foreign_key_set_should_raise_exception + assert_raise(ActiveRecord::HasAndBelongsToManyAssociationForeignKeyNeeded) { + Member.class_eval do + has_and_belongs_to_many :friends, :class_name => "Member", :join_table => "member_friends" + end + } + end uses_mocha 'mocking Post.transaction' do def test_association_proxy_transaction_method_starts_transaction_in_association_class -- 1.5.5.4