Permalink
Browse files

raises exception (ActiveRecord::ConfigurationError with message) on h…

…abtm association creation if join table contains a primary key

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
  • Loading branch information...
bellmyer authored and jeremy committed Feb 26, 2009
1 parent e972acc commit 9a3a7983c3f2998bcd9bb53944c61ef2406e7c59
@@ -29,6 +29,10 @@ def count_records
end
def insert_record(record, force = true, validate = true)
+ if ActiveRecord::Base.connection.supports_primary_key? && ActiveRecord::Base.connection.primary_key(@reflection.options[:join_table])
+ raise ActiveRecord::ConfigurationError, "Primary key is not allowed in a has_and_belongs_to_many join table (#{@reflection.options[:join_table]})."
+ end
+
if record.new_record?
if force
record.save!
@@ -54,6 +54,13 @@ def supports_migrations?
false
end
+ # Can this adapter determine the primary key for tables not attached
+ # to an ActiveRecord class, such as join tables? Backend specific, as
+ # the abstract adapter always returns +false+.
+ def supports_primary_key?
+ false
+ end
+
# Does this adapter support using DISTINCT within COUNT? This is +true+
# for all adapters except sqlite.
def supports_count_distinct?
@@ -207,6 +207,10 @@ def supports_migrations? #:nodoc:
true
end
+ def supports_primary_key? #:nodoc:
+ true
+ end
+
def supports_savepoints? #:nodoc:
true
end
@@ -549,6 +553,12 @@ def pk_and_sequence_for(table) #:nodoc:
keys.length == 1 ? [keys.first, nil] : nil
end
+ # Returns just a table's primary key
+ def primary_key(table)
+ pk_and_sequence = pk_and_sequence_for(table)
+ pk_and_sequence && pk_and_sequence.first
+ end
+
def case_sensitive_equality_operator
"= BINARY"
end
@@ -249,6 +249,11 @@ def supports_migrations?
true
end
+ # Does PostgreSQL support finding primary key on non-ActiveRecord tables?
+ def supports_primary_key? #:nodoc:
+ true
+ end
+
# Does PostgreSQL support standard conforming strings?
def supports_standard_conforming_strings?
# Temporarily set the client message level above error to prevent unintentional
@@ -810,6 +815,12 @@ def pk_and_sequence_for(table) #:nodoc:
nil
end
+ # Returns just a table's primary key
+ def primary_key(table)
+ pk_and_sequence = pk_and_sequence_for(table)
+ pk_and_sequence && pk_and_sequence.first
+ end
+
# Renames a table.
def rename_table(name, new_name)
execute "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
@@ -108,6 +108,10 @@ def supports_migrations? #:nodoc:
true
end
+ def supports_primary_key? #:nodoc:
+ true
+ end
+
def requires_reloading?
true
end
@@ -0,0 +1,45 @@
+require 'cases/helper'
+
+class MyReader < ActiveRecord::Base
+ has_and_belongs_to_many :my_books
+end
+
+class MyBook < ActiveRecord::Base
+ has_and_belongs_to_many :my_readers
+end
+
+class JoinTableTest < ActiveRecord::TestCase
+ def setup
+ ActiveRecord::Base.connection.create_table :my_books, :force => true do |t|
+ t.string :name
+ end
+ assert ActiveRecord::Base.connection.table_exists?(:my_books)
+
+ ActiveRecord::Base.connection.create_table :my_readers, :force => true do |t|
+ t.string :name
+ end
+ assert ActiveRecord::Base.connection.table_exists?(:my_readers)
+
+ ActiveRecord::Base.connection.create_table :my_books_my_readers, :force => true do |t|
+ t.integer :my_book_id
+ t.integer :my_reader_id
+ end
+ assert ActiveRecord::Base.connection.table_exists?(:my_books_my_readers)
+ end
+
+ def teardown
+ ActiveRecord::Base.connection.drop_table :my_books
+ ActiveRecord::Base.connection.drop_table :my_readers
+ ActiveRecord::Base.connection.drop_table :my_books_my_readers
+ end
+
+ uses_transaction :test_should_raise_exception_when_join_table_has_a_primary_key
+ def test_should_raise_exception_when_join_table_has_a_primary_key
+ if ActiveRecord::Base.connection.supports_primary_key?
+ assert_raise ActiveRecord::ConfigurationError do
+ jaime = MyReader.create(:name=>"Jaime")
+ jaime.my_books << MyBook.create(:name=>'Great Expectations')
+ end
+ end
+ end
+end
@@ -98,4 +98,22 @@ def test_instance_update_should_quote_pkey
def test_instance_destroy_should_quote_pkey
assert_nothing_raised { MixedCaseMonkey.find(1).destroy }
end
+
+ def test_supports_primary_key
+ assert_nothing_raised NoMethodError do
+ ActiveRecord::Base.connection.supports_primary_key?
+ end
+ end
+
+ def test_primary_key_returns_value_if_it_exists
+ if ActiveRecord::Base.connection.supports_primary_key?
+ assert_equal 'id', ActiveRecord::Base.connection.primary_key('developers')
+ end
+ end
+
+ def test_primary_key_returns_nil_if_it_does_not_exist
+ if ActiveRecord::Base.connection.supports_primary_key?
+ assert_nil ActiveRecord::Base.connection.primary_key('developers_projects')
+ end
+ end
end

0 comments on commit 9a3a798

Please sign in to comment.