aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG.md7
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb4
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb2
-rw-r--r--activerecord/test/cases/migration/change_schema_test.rb31
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb5
-rw-r--r--guides/source/4_2_release_notes.md3
9 files changed, 60 insertions, 5 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 28441e598e..6494c7374e 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,10 @@
+* Introduce `force: :cascade` option for `create_table`. Using this option
+ will recreate tables even if they have dependent objects (like foreign keys).
+ `db/schema.rb` now uses `force: :cascade`. This makes it possible to
+ reload the schema when foreign keys are in place.
+
+ *Matthew Draper*, *Yves Senn*
+
* `db:schema:load` and `db:structure:load` no longer purge the database
before loading the schema. This is left for the user to do.
`db:test:prepare` will still purge the database.
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 fd52cdf716..b340e8334b 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -132,6 +132,7 @@ module ActiveRecord
# Make a temporary table.
# [<tt>:force</tt>]
# Set to true to drop the table before creating it.
+ # Set to +:cascade+ to drop dependent objects as well.
# Defaults to false.
# [<tt>:as</tt>]
# SQL to use to generate the table. When this option is used, the block is
@@ -361,8 +362,12 @@ module ActiveRecord
# Drops a table from the database.
#
- # Although this command ignores +options+ and the block if one is given, it can be helpful
- # to provide these in a migration's +change+ method so it can be reverted.
+ # [<tt>:force</tt>]
+ # Set to +:cascade+ to drop dependent objects as well.
+ # Defaults to false.
+ #
+ # Although this command ignores most +options+ and the block if one is given,
+ # it can be helpful to provide these in a migration's +change+ method so it can be reverted.
# In that case, +options+ and the block will be used by create_table.
def drop_table(table_name, options = {})
execute "DROP TABLE #{quote_table_name(table_name)}"
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 69582ebb6f..ced80bacc8 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -487,7 +487,7 @@ module ActiveRecord
end
def drop_table(table_name, options = {})
- execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}"
+ execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
end
def rename_index(table_name, old_name, new_name)
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 f29b793a3f..7ba5437474 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -120,6 +120,10 @@ module ActiveRecord
SQL
end
+ def drop_table(table_name, options = {})
+ execute "DROP TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
+ end
+
# Returns true if schema exists.
def schema_exists?(name)
exec_query(<<-SQL, 'SCHEMA').rows.first[0].to_i > 0
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 77aa2efc47..3c44a625cc 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -126,7 +126,7 @@ HEADER
else
tbl.print ", id: false"
end
- tbl.print ", force: true"
+ tbl.print ", force: :cascade"
tbl.puts " do |t|"
# then dump all non-primary key columns
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index 7b7532993c..d6deb6fb1f 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -130,7 +130,7 @@ class PostgresqlLargeKeysTest < ActiveRecord::TestCase
def test_omg
schema = dump_table_schema "big_serials"
- assert_match "create_table \"big_serials\", id: :bigserial, force: true", schema
+ assert_match "create_table \"big_serials\", id: :bigserial", schema
end
def teardown
diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb
index d91e7142b3..d774cfebc4 100644
--- a/activerecord/test/cases/migration/change_schema_test.rb
+++ b/activerecord/test/cases/migration/change_schema_test.rb
@@ -415,5 +415,36 @@ module ActiveRecord
yield
end
end
+
+ if ActiveRecord::Base.connection.supports_foreign_keys?
+ class ChangeSchemaWithDependentObjectsTest < ActiveRecord::TestCase
+ self.use_transactional_fixtures = false
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_table :trains
+ @connection.create_table(:wagons) { |t| t.references :train }
+ @connection.add_foreign_key :wagons, :trains
+ end
+
+ teardown do
+ [:wagons, :trains].each do |table|
+ @connection.drop_table(table) if @connection.table_exists?(table)
+ end
+ end
+
+ def test_create_table_with_force_cascade_drops_dependent_objects
+ skip "MySQL > 5.5 does not drop dependent objects with DROP TABLE CASCADE" if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
+ # can't re-create table referenced by foreign key
+ assert_raises(ActiveRecord::StatementInvalid) do
+ @connection.create_table :trains, force: true
+ end
+
+ # can recreate referenced table with force: :cascade
+ @connection.create_table :trains, force: :cascade
+ assert_equal [], @connection.foreign_keys(:wagons)
+ end
+ end
+ end
end
end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 01c686f934..a094136766 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -40,6 +40,11 @@ class SchemaDumperTest < ActiveRecord::TestCase
assert_no_match %r{create_table "schema_migrations"}, output
end
+ def test_schema_dump_uses_force_cascade_on_create_table
+ output = dump_table_schema "authors"
+ assert_match %r{create_table "authors", force: :cascade}, output
+ end
+
def test_schema_dump_excludes_sqlite_sequence
output = standard_dump
assert_no_match %r{create_table "sqlite_sequence"}, output
diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md
index d8700539c4..f5575ac523 100644
--- a/guides/source/4_2_release_notes.md
+++ b/guides/source/4_2_release_notes.md
@@ -662,6 +662,9 @@ Please refer to the [Changelog][active-record] for detailed changes.
### Notable changes
+* `SchemaDumper` uses `force: :cascade` on `create_table`. This makes it
+ possible to reload a schema when foreign keys are in place.
+
* Added a `:required` option to singular associations, which defines a
presence validation on the association.
([Pull Request](https://github.com/rails/rails/pull/16056))