diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index fe752126ad..0f2af2c6d2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -647,10 +647,11 @@ module ActiveRecord end def add_foreign_key(from_table, to_table, options = {}) + options[:column] ||= foreign_key_column_for(to_table) primary_key = options.fetch(:primary_key, "id") options = { - column: options.fetch(:column), + column: options[:column], primary_key: primary_key, name: foreign_key_name(from_table, options), dependent: options.fetch(:dependent, nil) @@ -661,17 +662,26 @@ module ActiveRecord execute schema_creation.accept at end - def remove_foreign_key(from_table, options = {}) + def remove_foreign_key(from_table, options_or_to_table = {}) + if options_or_to_table.is_a?(Hash) + options = options_or_to_table + else + options = { column: foreign_key_column_for(options_or_to_table) } + end + at = create_alter_table from_table at.drop_foreign_key foreign_key_name(from_table, options) execute schema_creation.accept at end + def foreign_key_column_for(table_name) # :nodoc: + "#{table_name.to_s.singularize}_id" + end + def foreign_key_name(table_name, options) # :nodoc: options.fetch(:name) do - column_name = options.fetch(:column) - "#{table_name}_#{column_name}_fk" + "#{table_name}_#{options.fetch(:column)}_fk" end end diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index bd66c941a2..ad726a3c02 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -170,13 +170,15 @@ module ActiveRecord end def invert_add_foreign_key(args) - from_table, _to_table, add_options = *args + from_table, to_table, add_options = *args add_options ||= {} if add_options[:name] options = {name: add_options[:name]} elsif add_options[:column] options = {column: add_options[:column]} + else + options = to_table end [:remove_foreign_key, [from_table, options]] diff --git a/activerecord/test/cases/migration/command_recorder_test.rb b/activerecord/test/cases/migration/command_recorder_test.rb index 64a1b9a84e..e955beae1a 100644 --- a/activerecord/test/cases/migration/command_recorder_test.rb +++ b/activerecord/test/cases/migration/command_recorder_test.rb @@ -271,6 +271,11 @@ module ActiveRecord assert_equal [:enable_extension, ['uuid-ossp'], nil], enable end + def test_invert_add_foreign_key + enable = @recorder.inverse_of :add_foreign_key, [:dogs, :people] + assert_equal [:remove_foreign_key, [:dogs, :people]], enable + end + def test_invert_add_foreign_key_with_column enable = @recorder.inverse_of :add_foreign_key, [:dogs, :people, column: "owner_id"] assert_equal [:remove_foreign_key, [:dogs, column: "owner_id"]], enable diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb index 5935062efb..a43f7e48c8 100644 --- a/activerecord/test/cases/migration/foreign_key_test.rb +++ b/activerecord/test/cases/migration/foreign_key_test.rb @@ -46,7 +46,21 @@ module ActiveRecord assert_equal "fk_name", fk.name end - def test_add_foreign_key + def test_add_foreign_key_inferes_column + @connection.add_foreign_key :astronauts, :rockets + + foreign_keys = @connection.foreign_keys("astronauts") + assert_equal 1, foreign_keys.size + + fk = foreign_keys.first + assert_equal "astronauts", fk.from_table + assert_equal "rockets", fk.to_table + assert_equal "rocket_id", fk.column + assert_equal "id", fk.primary_key + assert_equal "astronauts_rocket_id_fk", fk.name + end + + def test_add_foreign_key_with_column @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" foreign_keys = @connection.foreign_keys("astronauts") @@ -112,7 +126,15 @@ module ActiveRecord assert_equal :nullify, fk.dependent end - def test_remove_foreign_key + def test_remove_foreign_key_inferes_column + @connection.add_foreign_key :astronauts, :rockets + + assert_equal 1, @connection.foreign_keys("astronauts").size + @connection.remove_foreign_key :astronauts, :rockets + assert_equal [], @connection.foreign_keys("astronauts") + end + + def test_remove_foreign_key_by_column @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" assert_equal 1, @connection.foreign_keys("astronauts").size