From 48970b14f3d75572c7ca13c50ff522af698d5860 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 187caa1..1398119 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.source_reflection.class_name rescue nil}##{reflection.source_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