aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorYves Senn <yves.senn@gmail.com>2014-06-10 14:26:50 +0200
committerYves Senn <yves.senn@gmail.com>2014-06-26 22:03:48 +0200
commit402f303f1d938cf2c7781d7734c4ff8e6b874f35 (patch)
treed96eb08bab6f5fc63f9f8a9a7fe2086d24c9e7e4 /activerecord
parent69c711f38cac85e9c8bdbe286591bf88ef720bfa (diff)
downloadrails-402f303f1d938cf2c7781d7734c4ff8e6b874f35.tar.gz
rails-402f303f1d938cf2c7781d7734c4ff8e6b874f35.tar.bz2
rails-402f303f1d938cf2c7781d7734c4ff8e6b874f35.zip
fk: support dependent option (:delete, :nullify and :restrict).
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb13
-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.rb14
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb9
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb2
-rw-r--r--activerecord/test/cases/migration/foreign_key_test.rb42
7 files changed, 83 insertions, 4 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 ad62eab4d2..57790d5667 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_creation.rb
@@ -19,11 +19,13 @@ module ActiveRecord
end
def visit_AddForeignKey(o)
- <<-SQL
+ sql = <<-SQL
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 << " #{dependency_sql(o.dependent)}" if o.dependent
+ sql
end
def visit_DropForeignKey(name)
@@ -98,6 +100,15 @@ FOREIGN KEY (#{quote_column_name(o.column)})
def options_include_default?(options)
options.include?(:default) && !(options[:null] == false && options[:default].nil?)
end
+
+ def dependency_sql(dependency)
+ case dependency
+ when :nullify then "ON DELETE SET NULL"
+ when :delete then "ON DELETE CASCADE"
+ when :restrict then "ON DELETE RESTRICT"
+ else ""
+ end
+ end
end
end
end
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 c18ebf1014..66ebf82971 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -37,6 +37,10 @@ module ActiveRecord
def primary_key
options[:primary_key]
end
+
+ def dependent
+ options[:dependent]
+ 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 db04ebc802..fe752126ad 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -652,7 +652,8 @@ module ActiveRecord
options = {
column: options.fetch(:column),
primary_key: primary_key,
- name: foreign_key_name(from_table, options)
+ name: foreign_key_name(from_table, options),
+ dependent: options.fetch(:dependent, nil)
}
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 6ba226765c..9610296043 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -524,7 +524,19 @@ module ActiveRecord
create_table_info = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
fk_info.map do |row|
- options = {column: row['column'], name: row['name'], primary_key: row['primary_key']}
+ options = {
+ column: row['column'],
+ name: row['name'],
+ 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[:dependent] = case $1
+ when 'CASCADE' then :delete
+ when 'SET NULL' then :nullify
+ end
+ end
+
ForeignKeyDefinition.new(table_name, row['to_table'], options)
end
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 c061337e71..7b61ff81ba 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -467,7 +467,14 @@ ORDER BY c.conname
options = {
column: row['column'],
name: row['name'],
- primary_key: row['primary_key'] }
+ primary_key: row['primary_key']
+ }
+
+ options[:dependent] = case row['dependency']
+ when 'c'; :delete
+ when 'n'; :nullify
+ when 'r'; :restrict
+ end
ForeignKeyDefinition.new(table_name, row["to_table"], options)
end
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 3db36458db..c415236c45 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -226,6 +226,8 @@ HEADER
'primary_key: ' + foreign_key.primary_key.inspect,
'name: ' + foreign_key.name.inspect
]
+ parts << ('dependent: ' + foreign_key.dependent.inspect) if foreign_key.dependent
+
' ' + parts.join(', ')
end
diff --git a/activerecord/test/cases/migration/foreign_key_test.rb b/activerecord/test/cases/migration/foreign_key_test.rb
index f299762b42..fbdb921334 100644
--- a/activerecord/test/cases/migration/foreign_key_test.rb
+++ b/activerecord/test/cases/migration/foreign_key_test.rb
@@ -77,6 +77,41 @@ module ActiveRecord
end
end
+ def test_add_dependent_restrict_foreign_key
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", dependent: :restrict
+
+ foreign_keys = @connection.foreign_keys("astronauts")
+ assert_equal 1, foreign_keys.size
+
+ fk = foreign_keys.first
+ if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
+ # ON DELETE RESTRICT is the default on MySQL
+ assert_equal nil, fk.dependent
+ else
+ assert_equal :restrict, fk.dependent
+ end
+ end
+
+ def test_add_dependent_delete_foreign_key
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", dependent: :delete
+
+ foreign_keys = @connection.foreign_keys("astronauts")
+ assert_equal 1, foreign_keys.size
+
+ fk = foreign_keys.first
+ assert_equal :delete, fk.dependent
+ end
+
+ def test_add_dependent_nullify_foreign_key
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", dependent: :nullify
+
+ foreign_keys = @connection.foreign_keys("astronauts")
+ assert_equal 1, foreign_keys.size
+
+ fk = foreign_keys.first
+ assert_equal :nullify, fk.dependent
+ end
+
def test_remove_foreign_key
@connection.add_foreign_key :astronauts, :rockets, column: "rocket_id"
@@ -97,6 +132,13 @@ module ActiveRecord
output = dump_table_schema "fk_test_has_fk"
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_dependent_option
+ @connection.add_foreign_key :astronauts, :rockets, column: "rocket_id", dependent: :nullify
+
+ output = dump_table_schema "astronauts"
+ assert_match %r{\s+add_foreign_key "astronauts",.+dependent: :nullify$}, output
+ end
end
end
end