README.md in strong_migrations-0.4.1 vs README.md in strong_migrations-0.4.2
- old
+ new
@@ -48,11 +48,11 @@
#### Bad
ActiveRecord caches database columns at runtime, so if you drop a column, it can cause exceptions until your app reboots.
```ruby
-class RemoveSomeColumnFromUsers < ActiveRecord::Migration[5.2]
+class RemoveSomeColumnFromUsers < ActiveRecord::Migration[6.0]
def change
remove_column :users, :some_column
end
end
```
@@ -69,11 +69,11 @@
2. Deploy code
3. Write a migration to remove the column (wrap in `safety_assured` block)
```ruby
- class RemoveSomeColumnFromUsers < ActiveRecord::Migration[5.2]
+ class RemoveSomeColumnFromUsers < ActiveRecord::Migration[6.0]
def change
safety_assured { remove_column :users, :some_column }
end
end
```
@@ -85,11 +85,11 @@
#### Bad
Adding a column with a default value to an existing table causes the entire table to be rewritten.
```ruby
-class AddSomeColumnToUsers < ActiveRecord::Migration[5.2]
+class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :some_column, :text, default: "default_value"
end
end
```
@@ -99,11 +99,11 @@
#### Good
Instead, add the column without a default value, then change the default.
```ruby
-class AddSomeColumnToUsers < ActiveRecord::Migration[5.2]
+class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
def up
add_column :users, :some_column, :text
change_column_default :users, :some_column, "default_value"
end
@@ -120,11 +120,11 @@
#### Bad
Backfilling in the same transaction that alters a table locks the table for the [duration of the backfill](https://wework.github.io/data/2015/11/05/add-columns-with-default-values-to-large-tables-in-rails-postgres/).
```ruby
-class AddSomeColumnToUsers < ActiveRecord::Migration[5.2]
+class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :some_column, :text
User.update_all some_column: "default_value"
end
end
@@ -132,14 +132,14 @@
Also, running a single query to update data can cause issues for large tables.
#### Good
-There are three keys: batching, throttling, and running it outside a transaction. Use the Rails console or a separate migration with `disable_ddl_transaction!`.
+There are three keys to backfilling safely: batching, throttling, and running it outside a transaction. Use the Rails console or a separate migration with `disable_ddl_transaction!`.
```ruby
-class BackfillSomeColumn < ActiveRecord::Migration[5.2]
+class BackfillSomeColumn < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def change
User.unscoped.in_batches do |relation|
relation.update_all some_column: "default_value"
@@ -154,11 +154,11 @@
#### Bad
In Postgres, adding a non-concurrent index locks the table.
```ruby
-class AddSomeIndexToUsers < ActiveRecord::Migration[5.2]
+class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
def change
add_index :users, :some_column
end
end
```
@@ -166,11 +166,11 @@
#### Good
Add indexes concurrently.
```ruby
-class AddSomeIndexToUsers < ActiveRecord::Migration[5.2]
+class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def change
add_index :users, :some_column, algorithm: :concurrently
end
@@ -184,11 +184,11 @@
#### Bad
Rails adds a non-concurrent index to references by default, which is problematic for Postgres.
```ruby
-class AddReferenceToUsers < ActiveRecord::Migration[5.2]
+class AddReferenceToUsers < ActiveRecord::Migration[6.0]
def change
add_reference :users, :city
end
end
```
@@ -196,16 +196,15 @@
#### Good
Make sure the index is added concurrently.
```ruby
-class AddReferenceToUsers < ActiveRecord::Migration[5.2]
+class AddReferenceToUsers < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def change
- add_reference :users, :city, index: false
- add_index :users, :city_id, algorithm: :concurrently
+ add_reference :users, :city, index: {algorithm: :concurrently}
end
end
```
For polymorphic references, add a compound index on type and id.
@@ -215,11 +214,11 @@
#### Bad
In Postgres, new foreign keys are validated by default, which acquires an `AccessExclusiveLock` that can be [expensive on large tables](https://travisofthenorth.com/blog/2017/2/2/postgres-adding-foreign-keys-with-zero-downtime).
```ruby
-class AddForeignKeyOnUsers < ActiveRecord::Migration[5.2]
+class AddForeignKeyOnUsers < ActiveRecord::Migration[6.0]
def change
add_foreign_key :users, :orders
end
end
```
@@ -229,21 +228,21 @@
Instead, validate it in a separate migration with a more agreeable `RowShareLock`. This approach is documented by Postgres to have “[the least impact on other work](https://www.postgresql.org/docs/current/sql-altertable.html).”
For Rails 5.2+, use:
```ruby
-class AddForeignKeyOnUsers < ActiveRecord::Migration[5.2]
+class AddForeignKeyOnUsers < ActiveRecord::Migration[6.0]
def change
add_foreign_key :users, :orders, validate: false
end
end
```
Then validate it in a separate migration.
```ruby
-class ValidateForeignKeyOnUsers < ActiveRecord::Migration[5.2]
+class ValidateForeignKeyOnUsers < ActiveRecord::Migration[6.0]
def change
validate_foreign_key :users, :orders
end
end
```
@@ -275,21 +274,21 @@
### Renaming or changing the type of a column
#### Bad
```ruby
-class RenameSomeColumn < ActiveRecord::Migration[5.2]
+class RenameSomeColumn < ActiveRecord::Migration[6.0]
def change
rename_column :users, :some_column, :new_name
end
end
```
or
```ruby
-class ChangeSomeColumnType < ActiveRecord::Migration[5.2]
+class ChangeSomeColumnType < ActiveRecord::Migration[6.0]
def change
change_column :users, :some_column, :new_type
end
end
```
@@ -310,11 +309,11 @@
### Renaming a table
#### Bad
```ruby
-class RenameUsersToCustomers < ActiveRecord::Migration[5.2]
+class RenameUsersToCustomers < ActiveRecord::Migration[6.0]
def change
rename_table :users, :customers
end
end
```
@@ -335,25 +334,25 @@
#### Bad
The `force` option can drop an existing table.
```ruby
-class CreateUsers < ActiveRecord::Migration[5.2]
+class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users, force: true do |t|
# ...
end
end
end
```
#### Good
-If you intend to drop a table, do it explicitly. Then create the new table without the `force` option:
+Create tables without the `force` option.
```ruby
-class CreateUsers < ActiveRecord::Migration[5.2]
+class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
# ...
end
end
@@ -365,11 +364,11 @@
#### Bad
This generates a single `UPDATE` statement to set the default value.
```ruby
-class ChangeSomeColumnNull < ActiveRecord::Migration[5.2]
+class ChangeSomeColumnNull < ActiveRecord::Migration[6.0]
def change
change_column_null :users, :some_column, false, "default_value"
end
end
```
@@ -377,11 +376,11 @@
#### Good
Backfill the column [safely](#backfilling-data). Then use:
```ruby
-class ChangeSomeColumnNull < ActiveRecord::Migration[5.2]
+class ChangeSomeColumnNull < ActiveRecord::Migration[6.0]
def change
change_column_null :users, :some_column, false
end
end
```
@@ -391,11 +390,11 @@
#### Bad
In Postgres, there’s no equality operator for the `json` column type, which causes issues for `SELECT DISTINCT` queries.
```ruby
-class AddPropertiesToUsers < ActiveRecord::Migration[5.2]
+class AddPropertiesToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :properties, :json
end
end
```
@@ -403,11 +402,11 @@
#### Good
Use `jsonb` instead.
```ruby
-class AddPropertiesToUsers < ActiveRecord::Migration[5.2]
+class AddPropertiesToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :properties, :jsonb
end
end
```
@@ -419,11 +418,11 @@
#### Bad
Adding a non-unique index with more than three columns rarely improves performance.
```ruby
-class AddSomeIndexToUsers < ActiveRecord::Migration[5.2]
+class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
def change
add_index :users, [:a, :b, :c, :d]
end
end
```
@@ -431,11 +430,11 @@
#### Good
Instead, start an index with columns that narrow down the results the most.
```ruby
-class AddSomeIndexToUsers < ActiveRecord::Migration[5.2]
+class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
def change
add_index :users, [:b, :d]
end
end
```
@@ -445,10 +444,10 @@
## Assuring Safety
To mark a step in the migration as safe, despite using a method that might otherwise be dangerous, wrap it in a `safety_assured` block.
```ruby
-class MySafeMigration < ActiveRecord::Migration[5.2]
+class MySafeMigration < ActiveRecord::Migration[6.0]
def change
safety_assured { remove_column :users, :some_column }
end
end
```