aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb19
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb1
-rw-r--r--activerecord/test/cases/migration/foreign_key_test.rb16
7 files changed, 46 insertions, 19 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
index aad4431910..b896bd25e4 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
@@ -24,7 +24,8 @@ ADD CONSTRAINT #{quote_column_name(o.name)}
FOREIGN KEY (#{quote_column_name(o.column)})
REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
SQL
- sql << " #{action_sql(o.on_delete)}" if o.on_delete
+ sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
+ sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
sql
end
@@ -101,7 +102,7 @@ FOREIGN KEY (#{quote_column_name(o.column)})
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
end
- def action_sql(action = "DELETE", dependency)
+ def action_sql(action, dependency)
case dependency
when :nullify then "ON #{action} SET NULL"
when :cascade then "ON #{action} CASCADE"
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 2d6cf2427c..2e47e68754 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -41,6 +41,10 @@ module ActiveRecord
def on_delete
options[:on_delete]
end
+
+ def on_update
+ options[:on_update]
+ end
end
# Represents the schema of an SQL table in an abstract way. This class
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 3f72e35bb5..18e73b0200 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -654,7 +654,8 @@ module ActiveRecord
column: options[:column],
primary_key: primary_key,
name: foreign_key_name(from_table, options),
- on_delete: options.fetch(:on_delete, nil)
+ on_delete: options[:on_delete],
+ on_update: options[:on_update]
}
at = create_alter_table from_table
at.add_foreign_key to_table, options
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index f3b7fe172e..868181e677 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -530,17 +530,22 @@ module ActiveRecord
primary_key: row['primary_key']
}
- if create_table_info =~ /CONSTRAINT #{quote_column_name(row['name'])} FOREIGN KEY .* REFERENCES .* ON DELETE (CASCADE|SET NULL|RESTRICT)/
- options[:on_delete] = case $1
- when 'CASCADE' then :cascade
- when 'SET NULL' then :nullify
- end
- end
+ options[:on_update] = extract_foreign_key_action(create_table_info, row['name'], "UPDATE")
+ options[:on_delete] = extract_foreign_key_action(create_table_info, row['name'], "DELETE")
ForeignKeyDefinition.new(table_name, row['to_table'], options)
end
end
+ def extract_foreign_key_action(structure, name, action) # :nodoc:
+ if structure =~ /CONSTRAINT #{quote_column_name(name)} FOREIGN KEY .* REFERENCES .* ON #{action} (CASCADE|SET NULL|RESTRICT)/
+ case $1
+ when 'CASCADE'; :cascade
+ when 'SET NULL'; :nullify
+ end
+ end
+ end
+
# Maps logical Rails types to MySQL-specific data types.
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
case type.to_s
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 bf87395ef1..7ffbe4434f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -450,7 +450,7 @@ module ActiveRecord
def foreign_keys(table_name)
fk_info = select_all <<-SQL
-SELECT t2.relname AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confdeltype AS dependency
+SELECT t2.relname AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
FROM pg_constraint c
JOIN pg_class t1 ON c.conrelid = t1.oid
JOIN pg_class t2 ON c.confrelid = t2.oid
@@ -470,12 +470,17 @@ ORDER BY c.conname
primary_key: row['primary_key']
}
- options[:on_delete] = case row['dependency']
- when 'c'; :cascade
- when 'n'; :nullify
- when 'r'; :restrict
- end
- ForeignKeyDefinition.new(table_name, row["to_table"], options)
+ options[:on_delete] = extract_foreign_key_action(row['on_delete'])
+ options[:on_update] = extract_foreign_key_action(row['on_update'])
+ ForeignKeyDefinition.new(table_name, row['to_table'], options)
+ end
+ end
+
+ def extract_foreign_key_action(specifier) # :nodoc:
+ case specifier
+ when 'c'; :cascade
+ when 'n'; :nullify
+ when 'r'; :restrict
end
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index cdbb374510..9b46f7751b 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -226,6 +226,7 @@ HEADER
'primary_key: ' + foreign_key.primary_key.inspect,
'name: ' + foreign_key.name.inspect
]
+ parts << ('on_update: ' + foreign_key.on_update.inspect) if foreign_key.on_update
parts << ('on_delete: ' + foreign_key.on_delete.inspect) if foreign_key.on_delete
' ' + parts.join(', ')
diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb
index f391e9ef41..c69fc18d82 100644
--- a/activerecord/test/cases/migration/foreign_key_test.rb
+++ b/activerecord/test/cases/migration/foreign_key_test.rb
@@ -126,6 +126,16 @@ module ActiveRecord
assert_equal :nullify, fk.on_delete
end
+ def test_add_foreign_key_with_on_update
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_update: :nullify
+
+ foreign_keys = @connection.foreign_keys("astronauts")
+ assert_equal 1, foreign_keys.size
+
+ fk = foreign_keys.first
+ assert_equal :nullify, fk.on_update
+ end
+
def test_remove_foreign_key_inferes_column
@connection.add_foreign_key :astronauts, :rockets
@@ -155,11 +165,11 @@ module ActiveRecord
assert_match %r{\s+add_foreign_key "fk_test_has_fk", "fk_test_has_pk", column: "fk_id", primary_key: "id", name: "fk_name"$}, output
end
- def test_schema_dumping_on_delete_option
- @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :nullify
+ def test_schema_dumping_on_delete_and_on_update_options
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", on_delete: :nullify, on_update: :cascade
output = dump_table_schema "astronauts"
- assert_match %r{\s+add_foreign_key "astronauts",.+on_delete: :nullify$}, output
+ assert_match %r{\s+add_foreign_key "astronauts",.+on_update: :cascade,.+on_delete: :nullify$}, output
end
class CreateCitiesAndHousesMigration < ActiveRecord::Migration