README.md in strong_migrations-1.8.0 vs README.md in strong_migrations-2.0.0
- old
+ new
@@ -62,11 +62,11 @@
- [removing a column](#removing-a-column)
- [changing the type of a column](#changing-the-type-of-a-column)
- [renaming a column](#renaming-a-column)
- [renaming a table](#renaming-a-table)
- [creating a table with the force option](#creating-a-table-with-the-force-option)
-- [adding an auto-incrementing column](#adding-an-auto-incrementing-column) [unreleased]
+- [adding an auto-incrementing column](#adding-an-auto-incrementing-column)
- [adding a stored generated column](#adding-a-stored-generated-column)
- [adding a check constraint](#adding-a-check-constraint)
- [executing SQL directly](#executing-SQL-directly)
- [backfilling data](#backfilling-data)
@@ -77,11 +77,11 @@
- [adding a foreign key](#adding-a-foreign-key)
- [adding a unique constraint](#adding-a-unique-constraint)
- [adding an exclusion constraint](#adding-an-exclusion-constraint)
- [adding a json column](#adding-a-json-column)
- [setting NOT NULL on an existing column](#setting-not-null-on-an-existing-column)
-- [adding a column with a default value](#adding-a-column-with-a-default-value)
+- [adding a column with a volatile default value](#adding-a-column-with-a-volatile-default-value)
Config-specific checks:
- [changing the default value of a column](#changing-the-default-value-of-a-column)
@@ -504,11 +504,11 @@
#### Bad
In Postgres, adding a unique constraint creates a unique index, which blocks reads and writes.
```ruby
-class AddUniqueContraint < ActiveRecord::Migration[7.1]
+class AddUniqueConstraint < ActiveRecord::Migration[7.1]
def change
add_unique_constraint :users, :some_column
end
end
```
@@ -516,11 +516,11 @@
#### Good
Create a unique index concurrently, then use it for the constraint.
```ruby
-class AddUniqueContraint < ActiveRecord::Migration[7.1]
+class AddUniqueConstraint < ActiveRecord::Migration[7.1]
disable_ddl_transaction!
def up
add_index :users, :some_column, unique: true, algorithm: :concurrently
add_unique_constraint :users, using_index: "index_users_on_some_column"
@@ -537,11 +537,11 @@
#### Bad
In Postgres, adding an exclusion constraint blocks reads and writes while every row is checked.
```ruby
-class AddExclusionContraint < ActiveRecord::Migration[7.1]
+class AddExclusionConstraint < ActiveRecord::Migration[7.1]
def change
add_exclusion_constraint :users, "number WITH =", using: :gist
end
end
```
@@ -594,91 +594,53 @@
#### Good
Instead, add a check constraint.
-For Rails 6.1+, use:
-
```ruby
class SetSomeColumnNotNull < ActiveRecord::Migration[7.1]
def change
add_check_constraint :users, "some_column IS NOT NULL", name: "users_some_column_null", validate: false
end
end
```
-For Rails < 6.1, use:
+Then validate it in a separate migration. Once the check constraint is validated, you can safely set `NOT NULL` on the column and drop the check constraint.
```ruby
-class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
- def change
- safety_assured do
- execute 'ALTER TABLE "users" ADD CONSTRAINT "users_some_column_null" CHECK ("some_column" IS NOT NULL) NOT VALID'
- end
- end
-end
-```
-
-Then validate it in a separate migration. A `NOT NULL` check constraint is [functionally equivalent](https://medium.com/doctolib/adding-a-not-null-constraint-on-pg-faster-with-minimal-locking-38b2c00c4d1c) to setting `NOT NULL` on the column (but it won’t show up in `schema.rb` in Rails < 6.1). In Postgres 12+, once the check constraint is validated, you can safely set `NOT NULL` on the column and drop the check constraint.
-
-For Rails 6.1+, use:
-
-```ruby
class ValidateSomeColumnNotNull < ActiveRecord::Migration[7.1]
def change
validate_check_constraint :users, name: "users_some_column_null"
-
- # in Postgres 12+, you can then safely set NOT NULL on the column
change_column_null :users, :some_column, false
remove_check_constraint :users, name: "users_some_column_null"
end
end
```
-For Rails < 6.1, use:
+### Adding a column with a volatile default value
-```ruby
-class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
- def change
- safety_assured do
- execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
- end
-
- # in Postgres 12+, you can then safely set NOT NULL on the column
- change_column_null :users, :some_column, false
- safety_assured do
- execute 'ALTER TABLE "users" DROP CONSTRAINT "users_some_column_null"'
- end
- end
-end
-```
-
-### Adding a column with a default value
-
#### Bad
-In earlier versions of Postgres, adding a column with a default value to an existing table causes the entire table to be rewritten. During this time, reads and writes are blocked in Postgres.
+Adding a column with a volatile default value to an existing table causes the entire table to be rewritten. During this time, reads and writes are blocked.
```ruby
class AddSomeColumnToUsers < ActiveRecord::Migration[7.1]
def change
- add_column :users, :some_column, :text, default: "default_value"
+ add_column :users, :some_column, :uuid, default: "gen_random_uuid()"
end
end
```
-In Postgres 11+, this no longer requires a table rewrite and is safe (except for volatile functions like `gen_random_uuid()`).
-
#### Good
Instead, add the column without a default value, then change the default.
```ruby
class AddSomeColumnToUsers < ActiveRecord::Migration[7.1]
def up
- add_column :users, :some_column, :text
- change_column_default :users, :some_column, "default_value"
+ add_column :users, :some_column, :uuid
+ change_column_default :users, :some_column, from: nil, to: "gen_random_uuid()"
end
def down
remove_column :users, :some_column
end
@@ -736,11 +698,11 @@
Instead, start an index with columns that narrow down the results the most.
```ruby
class AddSomeIndexToUsers < ActiveRecord::Migration[7.1]
def change
- add_index :users, [:b, :d]
+ add_index :users, [:d, :b]
end
end
```
For Postgres, be sure to add them concurrently.
@@ -923,17 +885,17 @@
## Target Version
If your development database version is different from production, you can specify the production version so the right checks run in development.
```ruby
-StrongMigrations.target_version = 10 # or "8.0.12", "10.3.2", etc
+StrongMigrations.target_version = 10 # or 8.0, 10.5, etc
```
-The major version works well for Postgres, while the full version is recommended for MySQL and MariaDB.
+The major version works well for Postgres, while the major and minor version is recommended for MySQL and MariaDB.
For safety, this option only affects development and test environments. In other environments, the actual server version is always used.
-If your app has multiple databases with different versions, with Rails 6.1+, you can use:
+If your app has multiple databases with different versions, you can use:
```ruby
StrongMigrations.target_version = {primary: 13, catalog: 15}
```