From e2ef25710682d884b2e6f5e99d47f18eb7083c68 Mon Sep 17 00:00:00 2001 From: Yves Senn Date: Fri, 6 Jun 2014 17:24:46 +0200 Subject: fk: `add_foreign_key` and `remove_foreign_key` for PostgreSQL adapter. --- .../connection_adapters/abstract_adapter.rb | 5 +++ .../postgresql/schema_statements.rb | 27 ++++++++++++ .../connection_adapters/postgresql_adapter.rb | 4 ++ .../test/cases/migration/foreign_key_test.rb | 49 ++++++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 activerecord/test/cases/migration/foreign_key_test.rb (limited to 'activerecord') diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index cc494a7f40..294ed6d7bf 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -233,6 +233,11 @@ module ActiveRecord false end + # Does this adapter support creating foreign key constraints? + def supports_foreign_keys? + false + end + # This is meant to be implemented by the adapters that support extensions def disable_extension(name) end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index b2aeb3a058..f09ce113d6 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -448,6 +448,33 @@ module ActiveRecord execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}" end + def add_foreign_key(from_table, to_table, options = {}) + foreign_key_column = options.fetch(:column) + referenced_column = "id" + foreign_key_name = foreign_key_name(from_table, options) + execute <<-SQL +ALTER TABLE #{quote_table_name(from_table)} +ADD CONSTRAINT #{foreign_key_name} + FOREIGN KEY (#{quote_column_name(foreign_key_column)}) + REFERENCES #{quote_table_name(to_table)} (#{quote_column_name(referenced_column)}) + SQL + end + + def remove_foreign_key(from_table, options = {}) + foreign_key_name = foreign_key_name(from_table, options) + execute <<-SQL +ALTER TABLE #{quote_table_name(from_table)} +DROP CONSTRAINT #{foreign_key_name} + SQL + end + + def foreign_key_name(table_name, options) + options.fetch(:name) do + column_name = options.fetch(:column) + "#{table_name}_#{column_name}_fk" + end + end + def index_name_length 63 end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index be4ae47d09..34262cf91d 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -159,6 +159,10 @@ module ActiveRecord true end + def supports_foreign_keys? + true + end + def index_algorithms { concurrently: 'CONCURRENTLY' } end diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb new file mode 100644 index 0000000000..978d1a8cf1 --- /dev/null +++ b/activerecord/test/cases/migration/foreign_key_test.rb @@ -0,0 +1,49 @@ +require 'cases/helper' + +if ActiveRecord::Base.connection.supports_foreign_keys? +module ActiveRecord + class Migration + class ForeignKeyTest < ActiveRecord::TestCase + class Rocket < ActiveRecord::Base + end + + class Astronaut < ActiveRecord::Base + end + + setup do + @connection = ActiveRecord::Base.connection + @connection.create_table "rockets" do |t| + t.string :name + end + + @connection.create_table "astronauts" do |t| + t.string :name + t.references :rocket + end + end + + def test_add_foreign_key + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" + + assert_raises ActiveRecord::InvalidForeignKey do + Astronaut.create rocket_id: 33 + end + end + + def test_remove_foreign_key + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id" + @connection.remove_foreign_key :astronauts, column: "rocket_id" + + Astronaut.create rocket_id: 33 + end + + def test_remove_foreign_key_by_name + @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", name: "fancy_named_fk" + @connection.remove_foreign_key :astronauts, name: "fancy_named_fk" + + Astronaut.create rocket_id: 33 + end + end + end +end +end -- cgit v1.2.3