strong_migrations 0.6.5 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bad0ba9c075a7c3eae98fc8835b9e56863b3573a381371d3b1affde769da0ad6
4
- data.tar.gz: 7d67dbdaf674414b43781dd45b60f1f0d11a6d811ffe9ce8235ffed2889d8383
3
+ metadata.gz: 947dda0ab2fa336611335b258b4eae34e7b60f38083e162fb6bf80d2237ce819
4
+ data.tar.gz: 6744411d6b2a33d5ee54b910ef60652fcb992cbb700a59a31da3eb48c2cb5322
5
5
  SHA512:
6
- metadata.gz: dc889f4d62bba08ae0d628e629dc37d7ecd53300ae92691118ca3db0707a416e7f043bbde41f2a0311acb9bd0f0b973175413f17a7c8aed2e134a6f29fc59b61
7
- data.tar.gz: b08c078f6591b4458fadf64c9d1b8e04c3323c8dc9036e88e4e5a7ddc4f8a38bfa39d8e3e0cce2dcda7b9b9fce2d9676140d0cf89b2d668f6e5f2389e825b225
6
+ metadata.gz: 3e1b51f910a02835ab0612f8be9714dce1dd1024acc3745a4465588447e6e12d8a4bdb2903c66f9c5f8ccc67bb6877ec231ad5979b304aff0ee34e5e4bd1f0a2
7
+ data.tar.gz: e739903401b7787ad66a929ff1f67b0e0b4ff9366571d25ad0349f680bf013adad95be38a1fc71c4f4039174b4ef7ee30764a9786e6b8677597a0d2bd6434749
@@ -1,3 +1,31 @@
1
+ ## 0.7.1 (2020-07-27)
2
+
3
+ - Added `target_version` option to replace database-specific options
4
+
5
+ ## 0.7.0 (2020-07-22)
6
+
7
+ - Added `check_down` option
8
+ - Added check for `change_column` with `null: false`
9
+ - Added check for `validate_foreign_key`
10
+ - Improved error messages
11
+ - Made auto analyze less verbose in Postgres
12
+ - Decreasing the length limit of a `varchar` column or adding a limit is not safe in Postgres
13
+ - Removed safety checks for `db` rake tasks (Rails 5+ handles this)
14
+
15
+ ## 0.6.8 (2020-05-13)
16
+
17
+ - `change_column_null` on a column with a `NOT NULL` constraint is safe in Postgres 12+
18
+
19
+ ## 0.6.7 (2020-05-13)
20
+
21
+ - Improved comments in initializer
22
+ - Fixed string timeouts for Postgres
23
+
24
+ ## 0.6.6 (2020-05-08)
25
+
26
+ - Added warnings for missing and long lock timeouts
27
+ - Added install generator
28
+
1
29
  ## 0.6.5 (2020-05-06)
2
30
 
3
31
  - Fixed deprecation warnings with Ruby 2.7
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Bob Remeika and David Waller, 2015-2019 Andrew Kane
1
+ Copyright (c) 2013 Bob Remeika and David Waller, 2015-2020 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -18,7 +18,42 @@ Add this line to your application’s Gemfile:
18
18
  gem 'strong_migrations'
19
19
  ```
20
20
 
21
- We highly recommend [setting timeouts](#timeouts). You can [mark existing migrations as safe](#existing-migrations) as well.
21
+ And run:
22
+
23
+ ```sh
24
+ bundle install
25
+ rails generate strong_migrations:install
26
+ ```
27
+
28
+ Strong Migrations sets a long statement timeout for migrations so you can set a [short statement timeout](#app-timeouts) for your application.
29
+
30
+ ## How It Works
31
+
32
+ When you run a migration that’s potentially dangerous, you’ll see an error message like:
33
+
34
+ ```txt
35
+ === Dangerous operation detected #strong_migrations ===
36
+
37
+ Active Record caches attributes, which causes problems
38
+ when removing columns. Be sure to ignore the column:
39
+
40
+ class User < ApplicationRecord
41
+ self.ignored_columns = ["name"]
42
+ end
43
+
44
+ Deploy the code, then wrap this step in a safety_assured { ... } block.
45
+
46
+ class RemoveColumn < ActiveRecord::Migration[6.0]
47
+ def change
48
+ safety_assured { remove_column :users, :name }
49
+ end
50
+ end
51
+ ```
52
+
53
+ An operation is classified as dangerous if it either:
54
+
55
+ - Blocks reads or writes for more than a few seconds (after a lock is acquired)
56
+ - Has a good chance of causing application errors
22
57
 
23
58
  ## Checks
24
59
 
@@ -27,21 +62,19 @@ Potentially dangerous operations:
27
62
  - [removing a column](#removing-a-column)
28
63
  - [adding a column with a default value](#adding-a-column-with-a-default-value)
29
64
  - [backfilling data](#backfilling-data)
30
- - [changing the type of a column](#renaming-or-changing-the-type-of-a-column)
31
- - [renaming a column](#renaming-or-changing-the-type-of-a-column)
65
+ - [changing the type of a column](#changing-the-type-of-a-column)
66
+ - [renaming a column](#renaming-a-column)
32
67
  - [renaming a table](#renaming-a-table)
33
68
  - [creating a table with the force option](#creating-a-table-with-the-force-option)
34
- - [using change_column_null with a default value](#using-change_column_null-with-a-default-value)
69
+ - [setting NOT NULL on an existing column](#setting-not-null-on-an-existing-column)
35
70
  - [executing SQL directly](#executing-SQL-directly)
36
71
 
37
72
  Postgres-specific checks:
38
73
 
39
- - [adding an index non-concurrently](#adding-an-index)
40
- - [removing an index non-concurrently](#removing-an-index)
74
+ - [adding an index non-concurrently](#adding-an-index-non-concurrently)
41
75
  - [adding a reference](#adding-a-reference)
42
76
  - [adding a foreign key](#adding-a-foreign-key)
43
77
  - [adding a json column](#adding-a-json-column)
44
- - [setting NOT NULL on an existing column](#setting-not-null-on-an-existing-column)
45
78
 
46
79
  Best practices:
47
80
 
@@ -53,7 +86,7 @@ You can also add [custom checks](#custom-checks) or [disable specific checks](#d
53
86
 
54
87
  #### Bad
55
88
 
56
- ActiveRecord caches database columns at runtime, so if you drop a column, it can cause exceptions until your app reboots.
89
+ Active Record caches database columns at runtime, so if you drop a column, it can cause exceptions until your app reboots.
57
90
 
58
91
  ```ruby
59
92
  class RemoveSomeColumnFromUsers < ActiveRecord::Migration[6.0]
@@ -65,7 +98,7 @@ end
65
98
 
66
99
  #### Good
67
100
 
68
- 1. Tell ActiveRecord to ignore the column from its cache
101
+ 1. Tell Active Record to ignore the column from its cache
69
102
 
70
103
  ```ruby
71
104
  class User < ApplicationRecord
@@ -88,11 +121,9 @@ end
88
121
 
89
122
  ### Adding a column with a default value
90
123
 
91
- Note: This operation is safe in Postgres 11+, MySQL 8.0.12+, and MariaDB 10.3.2+.
92
-
93
124
  #### Bad
94
125
 
95
- Adding a column with a default value to an existing table causes the entire table to be rewritten.
126
+ In earlier versions of Postgres, MySQL, and MariaDB, 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, and writes are blocked in MySQL and MariaDB.
96
127
 
97
128
  ```ruby
98
129
  class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
@@ -102,6 +133,8 @@ class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
102
133
  end
103
134
  ```
104
135
 
136
+ In Postgres 11+, MySQL 8.0.12+, and MariaDB 10.3.2+, this no longer requires a table rewrite and is safe.
137
+
105
138
  #### Good
106
139
 
107
140
  Instead, add the column without a default value, then change the default.
@@ -125,7 +158,7 @@ See the next section for how to backfill.
125
158
 
126
159
  #### Bad
127
160
 
128
- 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/).
161
+ Active Record creates a transaction around each migration, and backfilling in the same transaction that alters a table keeps the table locked 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/).
129
162
 
130
163
  ```ruby
131
164
  class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
@@ -155,19 +188,11 @@ class BackfillSomeColumn < ActiveRecord::Migration[6.0]
155
188
  end
156
189
  ```
157
190
 
158
- ### Renaming or changing the type of a column
191
+ ### Changing the type of a column
159
192
 
160
193
  #### Bad
161
194
 
162
- ```ruby
163
- class RenameSomeColumn < ActiveRecord::Migration[6.0]
164
- def change
165
- rename_column :users, :some_column, :new_name
166
- end
167
- end
168
- ```
169
-
170
- or
195
+ Changing the type of a column causes the entire table to be rewritten. During this time, reads and writes are blocked in Postgres, and writes are blocked in MySQL and MariaDB.
171
196
 
172
197
  ```ruby
173
198
  class ChangeSomeColumnType < ActiveRecord::Migration[6.0]
@@ -177,17 +202,44 @@ class ChangeSomeColumnType < ActiveRecord::Migration[6.0]
177
202
  end
178
203
  ```
179
204
 
180
- A few changes are safe in Postgres:
205
+ A few changes don’t require a table rewrite (and are safe) in Postgres:
181
206
 
182
- - Changing between `varchar` and `text` columns
207
+ - Increasing the length limit of a `varchar` column (or removing the limit)
208
+ - Changing a `varchar` column to a `text` column
209
+ - Changing a `text` column to a `varchar` column with no length limit
183
210
  - Increasing the precision of a `decimal` or `numeric` column
184
211
  - Making a `decimal` or `numeric` column unconstrained
185
212
  - Changing between `timestamp` and `timestamptz` columns when session time zone is UTC in Postgres 12+
186
213
 
187
214
  And a few in MySQL and MariaDB:
188
215
 
189
- - Increasing the length of a `varchar` column from under 255 up to 255
190
- - Increasing the length of a `varchar` column over 255
216
+ - Increasing the length limit of a `varchar` column from under 255 up to 255
217
+ - Increasing the length limit of a `varchar` column from over 255 to the max limit
218
+
219
+ #### Good
220
+
221
+ A safer approach is to:
222
+
223
+ 1. Create a new column
224
+ 2. Write to both columns
225
+ 3. Backfill data from the old column to the new column
226
+ 4. Move reads from the old column to the new column
227
+ 5. Stop writing to the old column
228
+ 6. Drop the old column
229
+
230
+ ### Renaming a column
231
+
232
+ #### Bad
233
+
234
+ Renaming a column that’s in use will cause errors in your application.
235
+
236
+ ```ruby
237
+ class RenameSomeColumn < ActiveRecord::Migration[6.0]
238
+ def change
239
+ rename_column :users, :some_column, :new_name
240
+ end
241
+ end
242
+ ```
191
243
 
192
244
  #### Good
193
245
 
@@ -204,6 +256,8 @@ A safer approach is to:
204
256
 
205
257
  #### Bad
206
258
 
259
+ Renaming a table that’s in use will cause errors in your application.
260
+
207
261
  ```ruby
208
262
  class RenameUsersToCustomers < ActiveRecord::Migration[6.0]
209
263
  def change
@@ -253,33 +307,57 @@ class CreateUsers < ActiveRecord::Migration[6.0]
253
307
  end
254
308
  ```
255
309
 
256
- ### Using change_column_null with a default value
310
+ If you intend to drop an existing table, run `drop_table` first.
311
+
312
+ ### Setting NOT NULL on an existing column
257
313
 
258
314
  #### Bad
259
315
 
260
- This generates a single `UPDATE` statement to set the default value.
316
+ Setting `NOT NULL` on an existing column blocks reads and writes while the every row is checked.
261
317
 
262
318
  ```ruby
263
- class ChangeSomeColumnNull < ActiveRecord::Migration[6.0]
319
+ class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
264
320
  def change
265
- change_column_null :users, :some_column, false, "default_value"
321
+ change_column_null :users, :some_column, false
266
322
  end
267
323
  end
268
324
  ```
269
325
 
270
- #### Good
326
+ #### Good - Postgres
327
+
328
+ Instead, add a check constraint:
329
+
330
+ ```ruby
331
+ class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
332
+ def change
333
+ safety_assured do
334
+ execute 'ALTER TABLE "users" ADD CONSTRAINT "users_some_column_null" CHECK ("some_column" IS NOT NULL) NOT VALID'
335
+ end
336
+ end
337
+ end
338
+ ```
271
339
 
272
- Backfill the column [safely](#backfilling-data). Then use:
340
+ 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 Postgres 12+, once the check constraint is validated, you can safely set `NOT NULL` on the column and drop the check constraint.
273
341
 
274
342
  ```ruby
275
- class ChangeSomeColumnNull < ActiveRecord::Migration[6.0]
343
+ class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
276
344
  def change
345
+ safety_assured do
346
+ execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
347
+ end
348
+
349
+ # in Postgres 12+, you can then safely set NOT NULL on the column
277
350
  change_column_null :users, :some_column, false
351
+ safety_assured do
352
+ execute 'ALTER TABLE "users" DROP CONSTRAINT "users_some_column_null"'
353
+ end
278
354
  end
279
355
  end
280
356
  ```
281
357
 
282
- Note: In Postgres, `change_column_null` is still [not safe](#setting-not-null-on-an-existing-column) with this method.
358
+ #### Good - MySQL and MariaDB
359
+
360
+ [Let us know](https://github.com/ankane/strong_migrations/issues/new) if you have a safe way to do this.
283
361
 
284
362
  ### Executing SQL directly
285
363
 
@@ -293,11 +371,11 @@ class ExecuteSQL < ActiveRecord::Migration[6.0]
293
371
  end
294
372
  ```
295
373
 
296
- ### Adding an index
374
+ ### Adding an index non-concurrently
297
375
 
298
376
  #### Bad
299
377
 
300
- In Postgres, adding an index non-concurrently locks the table.
378
+ In Postgres, adding an index non-concurrently blocks writes.
301
379
 
302
380
  ```ruby
303
381
  class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
@@ -329,41 +407,11 @@ With [gindex](https://github.com/ankane/gindex), you can generate an index migra
329
407
  rails g index table column
330
408
  ```
331
409
 
332
- ### Removing an index
333
-
334
- Note: This check is [opt-in](#opt-in-checks).
335
-
336
- #### Bad
337
-
338
- In Postgres, removing an index non-concurrently locks the table for a brief period.
339
-
340
- ```ruby
341
- class RemoveSomeIndexFromUsers < ActiveRecord::Migration[6.0]
342
- def change
343
- remove_index :users, :some_column
344
- end
345
- end
346
- ```
347
-
348
- #### Good
349
-
350
- Remove indexes concurrently.
351
-
352
- ```ruby
353
- class RemoveSomeIndexFromUsers < ActiveRecord::Migration[6.0]
354
- disable_ddl_transaction!
355
-
356
- def change
357
- remove_index :users, column: :some_column, algorithm: :concurrently
358
- end
359
- end
360
- ```
361
-
362
410
  ### Adding a reference
363
411
 
364
412
  #### Bad
365
413
 
366
- Rails adds an index non-concurrently to references by default, which is problematic for Postgres.
414
+ Rails adds an index non-concurrently to references by default, which blocks writes in Postgres.
367
415
 
368
416
  ```ruby
369
417
  class AddReferenceToUsers < ActiveRecord::Migration[6.0]
@@ -391,7 +439,7 @@ end
391
439
 
392
440
  #### Bad
393
441
 
394
- In Postgres, new foreign keys are validated by default, which acquires a `ShareRowExclusiveLock` that can be [expensive on large tables](https://travisofthenorth.com/blog/2017/2/2/postgres-adding-foreign-keys-with-zero-downtime).
442
+ In Postgres, adding a foreign key blocks writes on both tables.
395
443
 
396
444
  ```ruby
397
445
  class AddForeignKeyOnUsers < ActiveRecord::Migration[6.0]
@@ -413,7 +461,7 @@ end
413
461
 
414
462
  #### Good
415
463
 
416
- 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).”
464
+ Add the foreign key without validating existing rows, then validate them in a separate migration.
417
465
 
418
466
  For Rails 5.2+, use:
419
467
 
@@ -425,7 +473,7 @@ class AddForeignKeyOnUsers < ActiveRecord::Migration[6.0]
425
473
  end
426
474
  ```
427
475
 
428
- Then validate it in a separate migration.
476
+ Then:
429
477
 
430
478
  ```ruby
431
479
  class ValidateForeignKeyOnUsers < ActiveRecord::Migration[6.0]
@@ -447,7 +495,7 @@ class AddForeignKeyOnUsers < ActiveRecord::Migration[5.1]
447
495
  end
448
496
  ```
449
497
 
450
- Then validate it in a separate migration.
498
+ Then:
451
499
 
452
500
  ```ruby
453
501
  class ValidateForeignKeyOnUsers < ActiveRecord::Migration[5.1]
@@ -463,7 +511,7 @@ end
463
511
 
464
512
  #### Bad
465
513
 
466
- In Postgres, there’s no equality operator for the `json` column type, which can cause errors for existing `SELECT DISTINCT` queries.
514
+ In Postgres, there’s no equality operator for the `json` column type, which can cause errors for existing `SELECT DISTINCT` queries in your application.
467
515
 
468
516
  ```ruby
469
517
  class AddPropertiesToUsers < ActiveRecord::Migration[6.0]
@@ -485,48 +533,6 @@ class AddPropertiesToUsers < ActiveRecord::Migration[6.0]
485
533
  end
486
534
  ```
487
535
 
488
- ### Setting NOT NULL on an existing column
489
-
490
- #### Bad
491
-
492
- In Postgres, setting `NOT NULL` on an existing column requires an `AccessExclusiveLock`, which is expensive on large tables.
493
-
494
- ```ruby
495
- class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
496
- def change
497
- change_column_null :users, :some_column, false
498
- end
499
- end
500
- ```
501
-
502
- #### Good
503
-
504
- Instead, add a constraint:
505
-
506
- ```ruby
507
- class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
508
- def change
509
- safety_assured do
510
- execute 'ALTER TABLE "users" ADD CONSTRAINT "users_some_column_null" CHECK ("some_column" IS NOT NULL) NOT VALID'
511
- end
512
- end
513
- end
514
- ```
515
-
516
- Then validate it in a separate migration.
517
-
518
- ```ruby
519
- class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
520
- def change
521
- safety_assured do
522
- execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
523
- end
524
- end
525
- end
526
- ```
527
-
528
- Note: This is not 100% the same as `NOT NULL` column constraint. Here’s a [good explanation](https://medium.com/doctolib/adding-a-not-null-constraint-on-pg-faster-with-minimal-locking-38b2c00c4d1c).
529
-
530
536
  ### Keeping non-unique indexes to three columns or less
531
537
 
532
538
  #### Bad
@@ -587,16 +593,12 @@ Note: Since `remove_column` always requires a `safety_assured` block, it’s not
587
593
 
588
594
  ## Opt-in Checks
589
595
 
590
- Some operations rarely cause issues in practice, but can be checked if desired. Enable checks with:
591
-
592
- ```ruby
593
- StrongMigrations.enable_check(:remove_index)
594
- ```
596
+ ### Removing an index non-concurrently
595
597
 
596
- To start a check only after a specific migration, use:
598
+ Postgres supports removing indexes concurrently, but removing them non-concurrently shouldn’t be an issue for most applications. You can enable this check with:
597
599
 
598
600
  ```ruby
599
- StrongMigrations.enable_check(:remove_index, start_after: 20170101000000)
601
+ StrongMigrations.enable_check(:remove_index)
600
602
  ```
601
603
 
602
604
  ## Disable Checks
@@ -609,6 +611,14 @@ StrongMigrations.disable_check(:add_index)
609
611
 
610
612
  Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations.rb) for the list of keys.
611
613
 
614
+ ## Down Migrations / Rollbacks
615
+
616
+ By default, checks are disabled when migrating down. Enable them with:
617
+
618
+ ```ruby
619
+ StrongMigrations.check_down = true
620
+ ```
621
+
612
622
  ## Custom Messages
613
623
 
614
624
  To customize specific messages, create an initializer with:
@@ -619,26 +629,69 @@ StrongMigrations.error_messages[:add_column_default] = "Your custom instructions
619
629
 
620
630
  Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations.rb) for the list of keys.
621
631
 
622
- ## Timeouts
632
+ ## Migration Timeouts
623
633
 
624
- It’s a good idea to set a long statement timeout and a short lock timeout for migrations. This way, migrations can run for a while, and if a migration can’t acquire a lock in a timely manner, other statements won’t be stuck behind it.
634
+ It’s extremely important to set a short lock timeout for migrations. This way, if a migration can’t acquire a lock in a timely manner, other statements won’t be stuck behind it. We also recommend setting a long statement timeout so migrations can run for a while.
625
635
 
626
636
  Create `config/initializers/strong_migrations.rb` with:
627
637
 
628
638
  ```ruby
629
- StrongMigrations.statement_timeout = 1.hour
630
639
  StrongMigrations.lock_timeout = 10.seconds
640
+ StrongMigrations.statement_timeout = 1.hour
631
641
  ```
632
642
 
633
643
  Or set the timeouts directly on the database user that runs migrations. For Postgres, use:
634
644
 
635
645
  ```sql
636
- ALTER ROLE myuser SET statement_timeout = '1h';
637
646
  ALTER ROLE myuser SET lock_timeout = '10s';
647
+ ALTER ROLE myuser SET statement_timeout = '1h';
638
648
  ```
639
649
 
640
650
  Note: If you use PgBouncer in transaction mode, you must set timeouts on the database user.
641
651
 
652
+ ## App Timeouts
653
+
654
+ We recommend adding timeouts to `config/database.yml` to prevent connections from hanging and individual queries from taking up too many resources in controllers, jobs, the Rails console, and other places.
655
+
656
+ For Postgres:
657
+
658
+ ```yml
659
+ production:
660
+ connect_timeout: 5
661
+ variables:
662
+ statement_timeout: 15s
663
+ lock_timeout: 10s
664
+ ```
665
+
666
+ Note: If you use PgBouncer in transaction mode, you must set the statement and lock timeouts on the database user as shown above.
667
+
668
+ For MySQL:
669
+
670
+ ```yml
671
+ production:
672
+ connect_timeout: 5
673
+ read_timeout: 5
674
+ write_timeout: 5
675
+ variables:
676
+ max_execution_time: 15000 # ms
677
+ lock_wait_timeout: 10 # sec
678
+
679
+ ```
680
+
681
+ For MariaDB:
682
+
683
+ ```yml
684
+ production:
685
+ connect_timeout: 5
686
+ read_timeout: 5
687
+ write_timeout: 5
688
+ variables:
689
+ max_statement_time: 15 # sec
690
+ lock_wait_timeout: 10 # sec
691
+ ```
692
+
693
+ For HTTP connections, Redis, and other services, check out [this guide](https://github.com/ankane/the-ultimate-guide-to-ruby-timeouts).
694
+
642
695
  ## Existing Migrations
643
696
 
644
697
  To mark migrations as safe that were created before installing this gem, create an initializer with:
@@ -651,14 +704,14 @@ Use the version from your latest migration.
651
704
 
652
705
  ## Target Version
653
706
 
654
- If your development database version is different from production, you can specify the production version so the right checks are run in development.
707
+ If your development database version is different from production, you can specify the production version so the right checks run in development.
655
708
 
656
709
  ```ruby
657
- StrongMigrations.target_postgresql_version = "10"
658
- StrongMigrations.target_mysql_version = "8.0.12"
659
- StrongMigrations.target_mariadb_version = "10.3.2"
710
+ StrongMigrations.target_version = 10 # or "8.0.12", "10.3.2", etc
660
711
  ```
661
712
 
713
+ The major version works well for Postgres, while the full version is recommended for MySQL and MariaDB.
714
+
662
715
  For safety, this option only affects development and test environments. In other environments, the actual server version is always used.
663
716
 
664
717
  ## Analyze Tables
@@ -686,22 +739,20 @@ Columns can flip order in `db/schema.rb` when you have multiple developers. One
686
739
  task "db:schema:dump": "strong_migrations:alphabetize_columns"
687
740
  ```
688
741
 
689
- ## Dangerous Tasks
690
-
691
- For safety, dangerous database tasks are disabled in production - `db:drop`, `db:reset`, `db:schema:load`, and `db:structure:load`. To get around this, use:
692
-
693
- ```sh
694
- SAFETY_ASSURED=1 rails db:drop
695
- ```
696
-
697
742
  ## Permissions
698
743
 
699
744
  We recommend using a [separate database user](https://ankane.org/postgres-users) for migrations when possible so you don’t need to grant your app user permission to alter tables.
700
745
 
746
+ ## Smaller Projects
747
+
748
+ You probably don’t need this gem for smaller projects, as operations that are unsafe at scale can be perfectly safe on smaller, low-traffic tables.
749
+
701
750
  ## Additional Reading
702
751
 
703
752
  - [Rails Migrations with No Downtime](https://pedro.herokuapp.com/past/2011/7/13/rails_migrations_with_no_downtime/)
704
753
  - [PostgreSQL at Scale: Database Schema Changes Without Downtime](https://medium.com/braintree-product-technology/postgresql-at-scale-database-schema-changes-without-downtime-20d3749ed680)
754
+ - [An Overview of DDL Algorithms in MySQL](https://mydbops.wordpress.com/2020/03/04/an-overview-of-ddl-algorithms-in-mysql-covers-mysql-8/)
755
+ - [MariaDB InnoDB Online DDL Overview](https://mariadb.com/kb/en/innodb-online-ddl-overview/)
705
756
 
706
757
  ## Credits
707
758