Skip to content

Commit 65a2b74

Browse files
authored
Merge pull request rails#53863 from fatkodima/fix-if-exists-for-fkeys
Fix `if_exists`/`if_not_exists` for foreign keys addition and removal
2 parents 043e29e + 3f134a1 commit 65a2b74

File tree

3 files changed

+31
-5
lines changed

3 files changed

+31
-5
lines changed

activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,9 +1172,10 @@ def foreign_keys(table_name)
11721172
# +:deferred+ or +:immediate+ to specify the default behavior. Defaults to +false+.
11731173
def add_foreign_key(from_table, to_table, **options)
11741174
return unless use_foreign_keys?
1175-
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table, **options.slice(:column))
11761175

11771176
options = foreign_key_options(from_table, to_table, options)
1177+
return if options[:if_not_exists] == true && foreign_key_exists?(from_table, to_table, **options.slice(:column, :primary_key))
1178+
11781179
at = create_alter_table from_table
11791180
at.add_foreign_key to_table, options
11801181

@@ -1213,7 +1214,7 @@ def add_foreign_key(from_table, to_table, **options)
12131214
# The name of the table that contains the referenced primary key.
12141215
def remove_foreign_key(from_table, to_table = nil, **options)
12151216
return unless use_foreign_keys?
1216-
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
1217+
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table, **options.slice(:column))
12171218

12181219
fk_name_to_delete = foreign_key_for!(from_table, to_table: to_table, **options).name
12191220

activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def add_foreign_key(from_table, to_table, **options)
6363
end
6464

6565
def remove_foreign_key(from_table, to_table = nil, **options)
66-
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table)
66+
return if options.delete(:if_exists) == true && !foreign_key_exists?(from_table, to_table, **options.slice(:column))
6767

6868
to_table ||= options[:to_table]
6969
options = options.except(:name, :to_table, :validate)

activerecord/test/cases/migration/foreign_key_test.rb

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,31 @@ def test_add_foreign_key_with_column
235235
end
236236

237237
def test_add_foreign_key_with_if_not_exists_to_already_referenced_table
238-
@connection.add_foreign_key :astronauts, :rockets
239-
@connection.add_foreign_key :astronauts, :rockets, column: "favorite_rocket_id", if_not_exists: true
238+
@connection.add_foreign_key :astronauts, :rockets, column: "favorite_rocket_id"
239+
@connection.add_foreign_key :astronauts, :rockets, if_not_exists: true
240240

241241
foreign_keys = @connection.foreign_keys("astronauts")
242242
assert_equal 2, foreign_keys.size
243243
assert foreign_keys.all? { |fk| fk.to_table == "rockets" }
244244
assert_equal ["favorite_rocket_id", "rocket_id"], foreign_keys.map(&:column).sort
245245
end
246246

247+
def test_add_foreign_key_with_if_not_exists_considers_primary_key_option
248+
@connection.add_column :rockets, :id_for_type_change, :bigint
249+
250+
# Is needed to be able to reference by foreign key
251+
@connection.add_index :rockets, :id_for_type_change, unique: true
252+
253+
@connection.add_foreign_key :astronauts, :rockets
254+
@connection.add_foreign_key(:astronauts, :rockets, primary_key: :id_for_type_change,
255+
name: "custom_pk", if_not_exists: true)
256+
257+
foreign_keys = @connection.foreign_keys("astronauts")
258+
assert_equal 2, foreign_keys.size
259+
assert foreign_keys.all? { |fk| fk.to_table == "rockets" }
260+
assert_equal ["id", "id_for_type_change"], foreign_keys.map(&:primary_key).sort
261+
end
262+
247263
def test_add_foreign_key_with_non_standard_primary_key
248264
@connection.create_table :space_shuttles, id: false, force: true do |t|
249265
t.bigint :pk, primary_key: true
@@ -424,6 +440,15 @@ def test_remove_foreign_key_by_name
424440
assert_equal [], @connection.foreign_keys("astronauts")
425441
end
426442

443+
def test_remove_foreign_key_if_exists_and_custom_column
444+
@connection.add_column :astronauts, :myrocket_id, :bigint
445+
@connection.add_foreign_key :astronauts, :rockets
446+
assert_equal 1, @connection.foreign_keys("astronauts").size
447+
448+
@connection.remove_foreign_key :astronauts, :rockets, column: :myrocket_id, if_exists: true
449+
assert_equal 1, @connection.foreign_keys("astronauts").size
450+
end
451+
427452
def test_remove_foreign_non_existing_foreign_key_raises
428453
e = assert_raises ArgumentError do
429454
@connection.remove_foreign_key :astronauts, :rockets

0 commit comments

Comments
 (0)