File tree Expand file tree Collapse file tree 7 files changed +99
-0
lines changed
Expand file tree Collapse file tree 7 files changed +99
-0
lines changed Original file line number Diff line number Diff line change @@ -29,6 +29,10 @@ def count_records
2929 end
3030
3131 def insert_record ( record , force = true , validate = true )
32+ if ActiveRecord ::Base . connection . supports_primary_key? && ActiveRecord ::Base . connection . primary_key ( @reflection . options [ :join_table ] )
33+ raise ActiveRecord ::ConfigurationError , "Primary key is not allowed in a has_and_belongs_to_many join table (#{ @reflection . options [ :join_table ] } )."
34+ end
35+
3236 if record . new_record?
3337 if force
3438 record . save!
Original file line number Diff line number Diff line change @@ -56,6 +56,13 @@ def supports_migrations?
5656 false
5757 end
5858
59+ # Can this adapter determine the primary key for tables not attached
60+ # to an ActiveRecord class, such as join tables? Backend specific, as
61+ # the abstract adapter always returns +false+.
62+ def supports_primary_key?
63+ false
64+ end
65+
5966 # Does this adapter support using DISTINCT within COUNT? This is +true+
6067 # for all adapters except sqlite.
6168 def supports_count_distinct?
Original file line number Diff line number Diff line change @@ -208,6 +208,10 @@ def supports_migrations? #:nodoc:
208208 true
209209 end
210210
211+ def supports_primary_key? #:nodoc:
212+ true
213+ end
214+
211215 def supports_savepoints? #:nodoc:
212216 true
213217 end
@@ -550,6 +554,12 @@ def pk_and_sequence_for(table) #:nodoc:
550554 keys . length == 1 ? [ keys . first , nil ] : nil
551555 end
552556
557+ # Returns just a table's primary key
558+ def primary_key ( table )
559+ pk_and_sequence = pk_and_sequence_for ( table )
560+ pk_and_sequence && pk_and_sequence . first
561+ end
562+
553563 def case_sensitive_equality_operator
554564 "= BINARY"
555565 end
Original file line number Diff line number Diff line change @@ -250,6 +250,11 @@ def supports_migrations?
250250 true
251251 end
252252
253+ # Does PostgreSQL support finding primary key on non-ActiveRecord tables?
254+ def supports_primary_key? #:nodoc:
255+ true
256+ end
257+
253258 # Does PostgreSQL support standard conforming strings?
254259 def supports_standard_conforming_strings?
255260 # Temporarily set the client message level above error to prevent unintentional
@@ -811,6 +816,12 @@ def pk_and_sequence_for(table) #:nodoc:
811816 nil
812817 end
813818
819+ # Returns just a table's primary key
820+ def primary_key ( table )
821+ pk_and_sequence = pk_and_sequence_for ( table )
822+ pk_and_sequence && pk_and_sequence . first
823+ end
824+
814825 # Renames a table.
815826 def rename_table ( name , new_name )
816827 execute "ALTER TABLE #{ quote_table_name ( name ) } RENAME TO #{ quote_table_name ( new_name ) } "
Original file line number Diff line number Diff line change @@ -101,6 +101,10 @@ def supports_migrations? #:nodoc:
101101 true
102102 end
103103
104+ def supports_primary_key? #:nodoc:
105+ true
106+ end
107+
104108 def requires_reloading?
105109 true
106110 end
Original file line number Diff line number Diff line change 1+ require 'cases/helper'
2+
3+ class MyReader < ActiveRecord ::Base
4+ has_and_belongs_to_many :my_books
5+ end
6+
7+ class MyBook < ActiveRecord ::Base
8+ has_and_belongs_to_many :my_readers
9+ end
10+
11+ class JoinTableTest < ActiveRecord ::TestCase
12+ def setup
13+ ActiveRecord ::Base . connection . create_table :my_books , :force => true do |t |
14+ t . string :name
15+ end
16+ assert ActiveRecord ::Base . connection . table_exists? ( :my_books )
17+
18+ ActiveRecord ::Base . connection . create_table :my_readers , :force => true do |t |
19+ t . string :name
20+ end
21+ assert ActiveRecord ::Base . connection . table_exists? ( :my_readers )
22+
23+ ActiveRecord ::Base . connection . create_table :my_books_my_readers , :force => true do |t |
24+ t . integer :my_book_id
25+ t . integer :my_reader_id
26+ end
27+ assert ActiveRecord ::Base . connection . table_exists? ( :my_books_my_readers )
28+ end
29+
30+ def teardown
31+ ActiveRecord ::Base . connection . drop_table :my_books
32+ ActiveRecord ::Base . connection . drop_table :my_readers
33+ ActiveRecord ::Base . connection . drop_table :my_books_my_readers
34+ end
35+
36+ uses_transaction :test_should_raise_exception_when_join_table_has_a_primary_key
37+ def test_should_raise_exception_when_join_table_has_a_primary_key
38+ if ActiveRecord ::Base . connection . supports_primary_key?
39+ assert_raise ActiveRecord ::ConfigurationError do
40+ jaime = MyReader . create ( :name => "Jaime" )
41+ jaime . my_books << MyBook . create ( :name => 'Great Expectations' )
42+ end
43+ end
44+ end
45+ end
Original file line number Diff line number Diff line change @@ -98,4 +98,22 @@ def test_instance_update_should_quote_pkey
9898 def test_instance_destroy_should_quote_pkey
9999 assert_nothing_raised { MixedCaseMonkey . find ( 1 ) . destroy }
100100 end
101+
102+ def test_supports_primary_key
103+ assert_nothing_raised NoMethodError do
104+ ActiveRecord ::Base . connection . supports_primary_key?
105+ end
106+ end
107+
108+ def test_primary_key_returns_value_if_it_exists
109+ if ActiveRecord ::Base . connection . supports_primary_key?
110+ assert_equal 'id' , ActiveRecord ::Base . connection . primary_key ( 'developers' )
111+ end
112+ end
113+
114+ def test_primary_key_returns_nil_if_it_does_not_exist
115+ if ActiveRecord ::Base . connection . supports_primary_key?
116+ assert_nil ActiveRecord ::Base . connection . primary_key ( 'developers_projects' )
117+ end
118+ end
101119end
You can’t perform that action at this time.
0 commit comments