online_migrations 0.19.3 → 0.19.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +64 -64
- data/docs/background_data_migrations.md +1 -1
- data/docs/configuring.md +1 -1
- data/lib/generators/online_migrations/templates/background_schema_migrations_change_unique_index.rb.tt +9 -0
- data/lib/generators/online_migrations/templates/install_migration.rb.tt +2 -1
- data/lib/generators/online_migrations/upgrade_generator.rb +6 -0
- data/lib/online_migrations/background_schema_migrations/migration.rb +13 -3
- data/lib/online_migrations/background_schema_migrations/migration_helpers.rb +19 -3
- data/lib/online_migrations/background_schema_migrations/migration_runner.rb +7 -0
- data/lib/online_migrations/background_schema_migrations/scheduler.rb +3 -2
- data/lib/online_migrations/schema_statements.rb +24 -7
- data/lib/online_migrations/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6392ff9889da502701252f97a71e4fa8c3b403dc61aa010957a5b79221a9366b
|
4
|
+
data.tar.gz: 1c880f23e20b142c335679701bdac977f089ac5ef076352a438e6dfa469b54cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30f7c9ed855f97180ba1b4f9c90f717f58ad9198fbd90f1b80b914b35994a2b863499239263878115d220413927ca3f5a05519e917b66335a346607b19a8f2ab
|
7
|
+
data.tar.gz: 271a237cb9df14677ed5c364c6c90657a6726347ae94b6992ad37c468b0bf59a76e51c0a1b79f187264d2369637e6c6de83d454d6f8c1c368648640c5ee23068
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
## master (unreleased)
|
2
2
|
|
3
|
+
## 0.19.4 (2024-09-02)
|
4
|
+
|
5
|
+
- Fix an edge case for background schema migrations
|
6
|
+
|
7
|
+
If you use background schema migrations, you need to run
|
8
|
+
```
|
9
|
+
bin/rails generate online_migrations:upgrade
|
10
|
+
bin/rails db:migrate
|
11
|
+
```
|
12
|
+
|
13
|
+
- Fix retrying running stuck background schema migrations
|
14
|
+
- Fix renaming columns for tables with long names
|
15
|
+
|
3
16
|
## 0.19.3 (2024-08-09)
|
4
17
|
|
5
18
|
- Fix idempotency for `add_index`/`remove_index` for expression indexes
|
data/README.md
CHANGED
@@ -67,7 +67,7 @@ An operation is classified as dangerous if it either:
|
|
67
67
|
Consider the following migration:
|
68
68
|
|
69
69
|
```ruby
|
70
|
-
class AddAdminToUsers < ActiveRecord::Migration[7.
|
70
|
+
class AddAdminToUsers < ActiveRecord::Migration[7.2]
|
71
71
|
def change
|
72
72
|
add_column :users, :admin, :boolean, default: false, null: false
|
73
73
|
end
|
@@ -79,7 +79,7 @@ If the `users` table is large, running this migration on a live PostgreSQL < 11
|
|
79
79
|
A safer approach would be to run something like the following:
|
80
80
|
|
81
81
|
```ruby
|
82
|
-
class AddAdminToUsers < ActiveRecord::Migration[7.
|
82
|
+
class AddAdminToUsers < ActiveRecord::Migration[7.2]
|
83
83
|
# Do not wrap the migration in a transaction so that locks are held for a shorter time.
|
84
84
|
disable_ddl_transaction!
|
85
85
|
|
@@ -124,7 +124,7 @@ A safer approach is to:
|
|
124
124
|
|
125
125
|
add_column_with_default takes care of all this steps:
|
126
126
|
|
127
|
-
class AddAdminToUsers < ActiveRecord::Migration[7.
|
127
|
+
class AddAdminToUsers < ActiveRecord::Migration[7.2]
|
128
128
|
disable_ddl_transaction!
|
129
129
|
|
130
130
|
def change
|
@@ -178,7 +178,7 @@ You can also add [custom checks](docs/configuring.md#custom-checks) or [disable
|
|
178
178
|
Active Record caches database columns at runtime, so if you drop a column, it can cause exceptions until your app reboots.
|
179
179
|
|
180
180
|
```ruby
|
181
|
-
class RemoveNameFromUsers < ActiveRecord::Migration[7.
|
181
|
+
class RemoveNameFromUsers < ActiveRecord::Migration[7.2]
|
182
182
|
def change
|
183
183
|
remove_column :users, :name
|
184
184
|
end
|
@@ -199,7 +199,7 @@ end
|
|
199
199
|
3. Wrap column removing in a `safety_assured` block:
|
200
200
|
|
201
201
|
```ruby
|
202
|
-
class RemoveNameFromUsers < ActiveRecord::Migration[7.
|
202
|
+
class RemoveNameFromUsers < ActiveRecord::Migration[7.2]
|
203
203
|
def change
|
204
204
|
safety_assured { remove_column :users, :name }
|
205
205
|
end
|
@@ -216,7 +216,7 @@ end
|
|
216
216
|
In earlier versions of PostgreSQL adding a column with a non-null default value to an existing table blocks reads and writes while the entire table is rewritten.
|
217
217
|
|
218
218
|
```ruby
|
219
|
-
class AddAdminToUsers < ActiveRecord::Migration[7.
|
219
|
+
class AddAdminToUsers < ActiveRecord::Migration[7.2]
|
220
220
|
def change
|
221
221
|
add_column :users, :admin, :boolean, default: false
|
222
222
|
end
|
@@ -236,7 +236,7 @@ A safer approach is to:
|
|
236
236
|
`add_column_with_default` helper takes care of all this steps:
|
237
237
|
|
238
238
|
```ruby
|
239
|
-
class AddAdminToUsers < ActiveRecord::Migration[7.
|
239
|
+
class AddAdminToUsers < ActiveRecord::Migration[7.2]
|
240
240
|
disable_ddl_transaction!
|
241
241
|
|
242
242
|
def change
|
@@ -254,7 +254,7 @@ end
|
|
254
254
|
Active Record wraps each migration in a transaction, 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/).
|
255
255
|
|
256
256
|
```ruby
|
257
|
-
class AddAdminToUsers < ActiveRecord::Migration[7.
|
257
|
+
class AddAdminToUsers < ActiveRecord::Migration[7.2]
|
258
258
|
def change
|
259
259
|
add_column :users, :admin, :boolean
|
260
260
|
User.update_all(admin: false)
|
@@ -269,13 +269,13 @@ Also, running a single query to update data can cause issues for large tables.
|
|
269
269
|
There are three keys to backfilling safely: batching, throttling, and running it outside a transaction. Use a `update_column_in_batches` helper in a separate migration with `disable_ddl_transaction!`.
|
270
270
|
|
271
271
|
```ruby
|
272
|
-
class AddAdminToUsers < ActiveRecord::Migration[7.
|
272
|
+
class AddAdminToUsers < ActiveRecord::Migration[7.2]
|
273
273
|
def change
|
274
274
|
add_column :users, :admin, :boolean
|
275
275
|
end
|
276
276
|
end
|
277
277
|
|
278
|
-
class BackfillUsersAdminColumn < ActiveRecord::Migration[7.
|
278
|
+
class BackfillUsersAdminColumn < ActiveRecord::Migration[7.2]
|
279
279
|
disable_ddl_transaction!
|
280
280
|
|
281
281
|
def up
|
@@ -294,7 +294,7 @@ end
|
|
294
294
|
Changing the type of an existing column blocks reads and writes while the entire table is rewritten.
|
295
295
|
|
296
296
|
```ruby
|
297
|
-
class ChangeFilesSizeType < ActiveRecord::Migration[7.
|
297
|
+
class ChangeFilesSizeType < ActiveRecord::Migration[7.2]
|
298
298
|
def change
|
299
299
|
change_column :files, :size, :bigint
|
300
300
|
end
|
@@ -338,7 +338,7 @@ A safer approach can be accomplished in several steps:
|
|
338
338
|
1. Create a new column and keep column's data in sync:
|
339
339
|
|
340
340
|
```ruby
|
341
|
-
class InitializeChangeFilesSizeType < ActiveRecord::Migration[7.
|
341
|
+
class InitializeChangeFilesSizeType < ActiveRecord::Migration[7.2]
|
342
342
|
def change
|
343
343
|
initialize_column_type_change :files, :size, :bigint
|
344
344
|
end
|
@@ -351,7 +351,7 @@ A safer approach can be accomplished in several steps:
|
|
351
351
|
2. Backfill data from the old column to the new column:
|
352
352
|
|
353
353
|
```ruby
|
354
|
-
class BackfillChangeFilesSizeType < ActiveRecord::Migration[7.
|
354
|
+
class BackfillChangeFilesSizeType < ActiveRecord::Migration[7.2]
|
355
355
|
disable_ddl_transaction!
|
356
356
|
|
357
357
|
def up
|
@@ -372,7 +372,7 @@ during writes works automatically). For most column type changes, this does not
|
|
372
372
|
5. Copy indexes, foreign keys, check constraints, NOT NULL constraint, swap new column in place:
|
373
373
|
|
374
374
|
```ruby
|
375
|
-
class FinalizeChangeFilesSizeType < ActiveRecord::Migration[7.
|
375
|
+
class FinalizeChangeFilesSizeType < ActiveRecord::Migration[7.2]
|
376
376
|
disable_ddl_transaction!
|
377
377
|
|
378
378
|
def change
|
@@ -385,7 +385,7 @@ during writes works automatically). For most column type changes, this does not
|
|
385
385
|
7. Finally, if everything works as expected, remove copy trigger and old column:
|
386
386
|
|
387
387
|
```ruby
|
388
|
-
class CleanupChangeFilesSizeType < ActiveRecord::Migration[7.
|
388
|
+
class CleanupChangeFilesSizeType < ActiveRecord::Migration[7.2]
|
389
389
|
def up
|
390
390
|
cleanup_column_type_change :files, :size
|
391
391
|
end
|
@@ -406,7 +406,7 @@ during writes works automatically). For most column type changes, this does not
|
|
406
406
|
Renaming a column that's in use will cause errors in your application.
|
407
407
|
|
408
408
|
```ruby
|
409
|
-
class RenameUsersNameToFirstName < ActiveRecord::Migration[7.
|
409
|
+
class RenameUsersNameToFirstName < ActiveRecord::Migration[7.2]
|
410
410
|
def change
|
411
411
|
rename_column :users, :name, :first_name
|
412
412
|
end
|
@@ -477,7 +477,7 @@ nor any data/indexes/foreign keys copying will be made, so will be instantaneous
|
|
477
477
|
It will use a combination of a VIEW and column aliasing to work with both column names simultaneously
|
478
478
|
|
479
479
|
```ruby
|
480
|
-
class InitializeRenameUsersNameToFirstName < ActiveRecord::Migration[7.
|
480
|
+
class InitializeRenameUsersNameToFirstName < ActiveRecord::Migration[7.2]
|
481
481
|
def change
|
482
482
|
initialize_column_rename :users, :name, :first_name
|
483
483
|
end
|
@@ -500,7 +500,7 @@ It will use a combination of a VIEW and column aliasing to work with both column
|
|
500
500
|
9. Remove the VIEW created in step 3 and finally rename the column:
|
501
501
|
|
502
502
|
```ruby
|
503
|
-
class FinalizeRenameUsersNameToFirstName < ActiveRecord::Migration[7.
|
503
|
+
class FinalizeRenameUsersNameToFirstName < ActiveRecord::Migration[7.2]
|
504
504
|
def change
|
505
505
|
finalize_column_rename :users, :name, :first_name
|
506
506
|
end
|
@@ -516,7 +516,7 @@ It will use a combination of a VIEW and column aliasing to work with both column
|
|
516
516
|
Renaming a table that's in use will cause errors in your application.
|
517
517
|
|
518
518
|
```ruby
|
519
|
-
class RenameClientsToUsers < ActiveRecord::Migration[7.
|
519
|
+
class RenameClientsToUsers < ActiveRecord::Migration[7.2]
|
520
520
|
def change
|
521
521
|
rename_table :clients, :users
|
522
522
|
end
|
@@ -571,7 +571,7 @@ To work around this limitation, we need to tell Active Record to acquire this in
|
|
571
571
|
3. Create a VIEW:
|
572
572
|
|
573
573
|
```ruby
|
574
|
-
class InitializeRenameClientsToUsers < ActiveRecord::Migration[7.
|
574
|
+
class InitializeRenameClientsToUsers < ActiveRecord::Migration[7.2]
|
575
575
|
def change
|
576
576
|
initialize_table_rename :clients, :users
|
577
577
|
end
|
@@ -584,7 +584,7 @@ To work around this limitation, we need to tell Active Record to acquire this in
|
|
584
584
|
7. Remove the VIEW created in step 3:
|
585
585
|
|
586
586
|
```ruby
|
587
|
-
class FinalizeRenameClientsToUsers < ActiveRecord::Migration[7.
|
587
|
+
class FinalizeRenameClientsToUsers < ActiveRecord::Migration[7.2]
|
588
588
|
def change
|
589
589
|
finalize_table_rename :clients, :users
|
590
590
|
end
|
@@ -600,7 +600,7 @@ To work around this limitation, we need to tell Active Record to acquire this in
|
|
600
600
|
The `force` option can drop an existing table.
|
601
601
|
|
602
602
|
```ruby
|
603
|
-
class CreateUsers < ActiveRecord::Migration[7.
|
603
|
+
class CreateUsers < ActiveRecord::Migration[7.2]
|
604
604
|
def change
|
605
605
|
create_table :users, force: true do |t|
|
606
606
|
# ...
|
@@ -614,7 +614,7 @@ end
|
|
614
614
|
Create tables without the `force` option.
|
615
615
|
|
616
616
|
```ruby
|
617
|
-
class CreateUsers < ActiveRecord::Migration[7.
|
617
|
+
class CreateUsers < ActiveRecord::Migration[7.2]
|
618
618
|
def change
|
619
619
|
create_table :users do |t|
|
620
620
|
# ...
|
@@ -632,7 +632,7 @@ If you intend to drop an existing table, run `drop_table` first.
|
|
632
632
|
Adding a check constraint blocks reads and writes while every row is checked.
|
633
633
|
|
634
634
|
```ruby
|
635
|
-
class AddCheckConstraint < ActiveRecord::Migration[7.
|
635
|
+
class AddCheckConstraint < ActiveRecord::Migration[7.2]
|
636
636
|
def change
|
637
637
|
add_check_constraint :users, "char_length(name) >= 1", name: "name_check"
|
638
638
|
end
|
@@ -644,7 +644,7 @@ end
|
|
644
644
|
Add the check constraint without validating existing rows, and then validate them in a separate transaction:
|
645
645
|
|
646
646
|
```ruby
|
647
|
-
class AddCheckConstraint < ActiveRecord::Migration[7.
|
647
|
+
class AddCheckConstraint < ActiveRecord::Migration[7.2]
|
648
648
|
disable_ddl_transaction!
|
649
649
|
|
650
650
|
def change
|
@@ -663,7 +663,7 @@ end
|
|
663
663
|
Setting `NOT NULL` on an existing column blocks reads and writes while every row is checked.
|
664
664
|
|
665
665
|
```ruby
|
666
|
-
class ChangeUsersNameNull < ActiveRecord::Migration[7.
|
666
|
+
class ChangeUsersNameNull < ActiveRecord::Migration[7.2]
|
667
667
|
def change
|
668
668
|
change_column_null :users, :name, false
|
669
669
|
end
|
@@ -675,7 +675,7 @@ end
|
|
675
675
|
Instead, add a check constraint and validate it in a separate transaction:
|
676
676
|
|
677
677
|
```ruby
|
678
|
-
class ChangeUsersNameNull < ActiveRecord::Migration[7.
|
678
|
+
class ChangeUsersNameNull < ActiveRecord::Migration[7.2]
|
679
679
|
disable_ddl_transaction!
|
680
680
|
|
681
681
|
def change
|
@@ -690,7 +690,7 @@ end
|
|
690
690
|
A `NOT NULL` check constraint is functionally equivalent to setting `NOT NULL` on the column (but it won't show up in `schema.rb` in Rails < 6.1). In PostgreSQL 12+, once the check constraint is validated, you can safely set `NOT NULL` on the column and drop the check constraint.
|
691
691
|
|
692
692
|
```ruby
|
693
|
-
class ChangeUsersNameNullDropCheck < ActiveRecord::Migration[7.
|
693
|
+
class ChangeUsersNameNullDropCheck < ActiveRecord::Migration[7.2]
|
694
694
|
def change
|
695
695
|
# in PostgreSQL 12+, you can then safely set NOT NULL on the column
|
696
696
|
change_column_null :users, :name, false
|
@@ -704,7 +704,7 @@ end
|
|
704
704
|
Online Migrations does not support inspecting what happens inside an `execute` call, so cannot help you here. Make really sure that what you're doing is safe before proceeding, then wrap it in a `safety_assured { ... }` block:
|
705
705
|
|
706
706
|
```ruby
|
707
|
-
class ExecuteSQL < ActiveRecord::Migration[7.
|
707
|
+
class ExecuteSQL < ActiveRecord::Migration[7.2]
|
708
708
|
def change
|
709
709
|
safety_assured { execute "..." }
|
710
710
|
end
|
@@ -718,7 +718,7 @@ end
|
|
718
718
|
Adding an index non-concurrently blocks writes.
|
719
719
|
|
720
720
|
```ruby
|
721
|
-
class AddIndexOnUsersEmail < ActiveRecord::Migration[7.
|
721
|
+
class AddIndexOnUsersEmail < ActiveRecord::Migration[7.2]
|
722
722
|
def change
|
723
723
|
add_index :users, :email, unique: true
|
724
724
|
end
|
@@ -730,7 +730,7 @@ end
|
|
730
730
|
Add indexes concurrently.
|
731
731
|
|
732
732
|
```ruby
|
733
|
-
class AddIndexOnUsersEmail < ActiveRecord::Migration[7.
|
733
|
+
class AddIndexOnUsersEmail < ActiveRecord::Migration[7.2]
|
734
734
|
disable_ddl_transaction!
|
735
735
|
|
736
736
|
def change
|
@@ -748,7 +748,7 @@ end
|
|
748
748
|
While actual removing of an index is usually fast, removing it non-concurrently tries to obtain an `ACCESS EXCLUSIVE` lock on the table, waiting for all existing queries to complete and blocking all the subsequent queries (even `SELECT`s) on that table until the lock is obtained and index is removed.
|
749
749
|
|
750
750
|
```ruby
|
751
|
-
class RemoveIndexOnUsersEmail < ActiveRecord::Migration[7.
|
751
|
+
class RemoveIndexOnUsersEmail < ActiveRecord::Migration[7.2]
|
752
752
|
def change
|
753
753
|
remove_index :users, :email
|
754
754
|
end
|
@@ -760,7 +760,7 @@ end
|
|
760
760
|
Remove indexes concurrently.
|
761
761
|
|
762
762
|
```ruby
|
763
|
-
class RemoveIndexOnUsersEmail < ActiveRecord::Migration[7.
|
763
|
+
class RemoveIndexOnUsersEmail < ActiveRecord::Migration[7.2]
|
764
764
|
disable_ddl_transaction!
|
765
765
|
|
766
766
|
def change
|
@@ -778,7 +778,7 @@ end
|
|
778
778
|
Removing an old index before replacing it with the new one might result in slow queries while building the new index.
|
779
779
|
|
780
780
|
```ruby
|
781
|
-
class AddIndexOnCreationToProjects < ActiveRecord::Migration[7.
|
781
|
+
class AddIndexOnCreationToProjects < ActiveRecord::Migration[7.2]
|
782
782
|
disable_ddl_transaction!
|
783
783
|
|
784
784
|
def change
|
@@ -795,7 +795,7 @@ end
|
|
795
795
|
A safer approach is to create the new index and then delete the old one.
|
796
796
|
|
797
797
|
```ruby
|
798
|
-
class AddIndexOnCreationToProjects < ActiveRecord::Migration[7.
|
798
|
+
class AddIndexOnCreationToProjects < ActiveRecord::Migration[7.2]
|
799
799
|
disable_ddl_transaction!
|
800
800
|
|
801
801
|
def change
|
@@ -812,7 +812,7 @@ end
|
|
812
812
|
Rails adds an index non-concurrently to references by default, which blocks writes. Additionally, if `foreign_key` option (without `validate: false`) is provided, both tables are blocked while it is validated.
|
813
813
|
|
814
814
|
```ruby
|
815
|
-
class AddUserToProjects < ActiveRecord::Migration[7.
|
815
|
+
class AddUserToProjects < ActiveRecord::Migration[7.2]
|
816
816
|
def change
|
817
817
|
add_reference :projects, :user, foreign_key: true
|
818
818
|
end
|
@@ -825,7 +825,7 @@ Make sure the index is added concurrently and the foreign key is added in a sepa
|
|
825
825
|
Or you can use `add_reference_concurrently` helper. It will create a reference and take care of safely adding index and/or foreign key.
|
826
826
|
|
827
827
|
```ruby
|
828
|
-
class AddUserToProjects < ActiveRecord::Migration[7.
|
828
|
+
class AddUserToProjects < ActiveRecord::Migration[7.2]
|
829
829
|
disable_ddl_transaction!
|
830
830
|
|
831
831
|
def change
|
@@ -843,7 +843,7 @@ end
|
|
843
843
|
Adding a foreign key blocks writes on both tables.
|
844
844
|
|
845
845
|
```ruby
|
846
|
-
class AddForeignKeyToProjectsUser < ActiveRecord::Migration[7.
|
846
|
+
class AddForeignKeyToProjectsUser < ActiveRecord::Migration[7.2]
|
847
847
|
def change
|
848
848
|
add_foreign_key :projects, :users
|
849
849
|
end
|
@@ -853,7 +853,7 @@ end
|
|
853
853
|
or
|
854
854
|
|
855
855
|
```ruby
|
856
|
-
class AddReferenceToProjectsUser < ActiveRecord::Migration[7.
|
856
|
+
class AddReferenceToProjectsUser < ActiveRecord::Migration[7.2]
|
857
857
|
def change
|
858
858
|
add_reference :projects, :user, foreign_key: true
|
859
859
|
end
|
@@ -865,7 +865,7 @@ end
|
|
865
865
|
Add the foreign key without validating existing rows:
|
866
866
|
|
867
867
|
```ruby
|
868
|
-
class AddForeignKeyToProjectsUser < ActiveRecord::Migration[7.
|
868
|
+
class AddForeignKeyToProjectsUser < ActiveRecord::Migration[7.2]
|
869
869
|
def change
|
870
870
|
add_foreign_key :projects, :users, validate: false
|
871
871
|
end
|
@@ -875,7 +875,7 @@ end
|
|
875
875
|
Then validate them in a separate migration:
|
876
876
|
|
877
877
|
```ruby
|
878
|
-
class ValidateForeignKeyOnProjectsUser < ActiveRecord::Migration[7.
|
878
|
+
class ValidateForeignKeyOnProjectsUser < ActiveRecord::Migration[7.2]
|
879
879
|
def change
|
880
880
|
validate_foreign_key :projects, :users
|
881
881
|
end
|
@@ -889,7 +889,7 @@ end
|
|
889
889
|
Adding an exclusion constraint blocks reads and writes while every row is checked.
|
890
890
|
|
891
891
|
```ruby
|
892
|
-
class AddExclusionContraint < ActiveRecord::Migration[7.
|
892
|
+
class AddExclusionContraint < ActiveRecord::Migration[7.2]
|
893
893
|
def change
|
894
894
|
add_exclusion_constraint :users, "number WITH =", using: :gist
|
895
895
|
end
|
@@ -907,7 +907,7 @@ end
|
|
907
907
|
Adding a unique constraint blocks reads and writes while the underlying index is being built.
|
908
908
|
|
909
909
|
```ruby
|
910
|
-
class AddUniqueConstraint < ActiveRecord::Migration[7.
|
910
|
+
class AddUniqueConstraint < ActiveRecord::Migration[7.2]
|
911
911
|
def change
|
912
912
|
add_unique_constraint :sections, :position, deferrable: :deferred
|
913
913
|
end
|
@@ -919,7 +919,7 @@ end
|
|
919
919
|
A safer approach is to create a unique index first, and then create a unique key using that index.
|
920
920
|
|
921
921
|
```ruby
|
922
|
-
class AddUniqueConstraintAddIndex < ActiveRecord::Migration[7.
|
922
|
+
class AddUniqueConstraintAddIndex < ActiveRecord::Migration[7.2]
|
923
923
|
disable_ddl_transaction!
|
924
924
|
|
925
925
|
def change
|
@@ -929,7 +929,7 @@ end
|
|
929
929
|
```
|
930
930
|
|
931
931
|
```ruby
|
932
|
-
class AddUniqueConstraint < ActiveRecord::Migration[7.
|
932
|
+
class AddUniqueConstraint < ActiveRecord::Migration[7.2]
|
933
933
|
def up
|
934
934
|
add_unique_constraint :sections, :position, deferrable: :deferred, using_index: "index_sections_on_position"
|
935
935
|
end
|
@@ -947,7 +947,7 @@ end
|
|
947
947
|
There's no equality operator for the `json` column type, which can cause errors for existing `SELECT DISTINCT` queries in your application.
|
948
948
|
|
949
949
|
```ruby
|
950
|
-
class AddSettingsToProjects < ActiveRecord::Migration[7.
|
950
|
+
class AddSettingsToProjects < ActiveRecord::Migration[7.2]
|
951
951
|
def change
|
952
952
|
add_column :projects, :settings, :json
|
953
953
|
end
|
@@ -959,7 +959,7 @@ end
|
|
959
959
|
Use `jsonb` instead.
|
960
960
|
|
961
961
|
```ruby
|
962
|
-
class AddSettingsToProjects < ActiveRecord::Migration[7.
|
962
|
+
class AddSettingsToProjects < ActiveRecord::Migration[7.2]
|
963
963
|
def change
|
964
964
|
add_column :projects, :settings, :jsonb
|
965
965
|
end
|
@@ -973,7 +973,7 @@ end
|
|
973
973
|
Adding a stored generated column causes the entire table to be rewritten. During this time, reads and writes are blocked.
|
974
974
|
|
975
975
|
```ruby
|
976
|
-
class AddLowerEmailToUsers < ActiveRecord::Migration[7.
|
976
|
+
class AddLowerEmailToUsers < ActiveRecord::Migration[7.2]
|
977
977
|
def change
|
978
978
|
add_column :users, :lower_email, :virtual, type: :string, as: "LOWER(email)", stored: true
|
979
979
|
end
|
@@ -991,7 +991,7 @@ Add a non-generated column and use callbacks or triggers instead.
|
|
991
991
|
When using short integer types as primary key types, [there is a risk](https://m.signalvnoise.com/update-on-basecamp-3-being-stuck-in-read-only-as-of-nov-8-922am-cst/) of running out of IDs on inserts. The default type in Active Record < 5.1 for primary and foreign keys is `INTEGER`, which allows a little over of 2 billion records. Active Record 5.1 changed the default type to `BIGINT`.
|
992
992
|
|
993
993
|
```ruby
|
994
|
-
class CreateUsers < ActiveRecord::Migration[7.
|
994
|
+
class CreateUsers < ActiveRecord::Migration[7.2]
|
995
995
|
def change
|
996
996
|
create_table :users, id: :integer do |t|
|
997
997
|
# ...
|
@@ -1005,7 +1005,7 @@ end
|
|
1005
1005
|
Use one of `bigint`, `bigserial`, `uuid` instead.
|
1006
1006
|
|
1007
1007
|
```ruby
|
1008
|
-
class CreateUsers < ActiveRecord::Migration[7.
|
1008
|
+
class CreateUsers < ActiveRecord::Migration[7.2]
|
1009
1009
|
def change
|
1010
1010
|
create_table :users, id: :bigint do |t| # bigint is the default for Active Record >= 5.1
|
1011
1011
|
# ...
|
@@ -1021,7 +1021,7 @@ end
|
|
1021
1021
|
Hash index operations are not WAL-logged, so hash indexes might need to be rebuilt with `REINDEX` after a database crash if there were unwritten changes. Also, changes to hash indexes are not replicated over streaming or file-based replication after the initial base backup, so they give wrong answers to queries that subsequently use them. For these reasons, hash index use is discouraged.
|
1022
1022
|
|
1023
1023
|
```ruby
|
1024
|
-
class AddIndexToUsersOnEmail < ActiveRecord::Migration[7.
|
1024
|
+
class AddIndexToUsersOnEmail < ActiveRecord::Migration[7.2]
|
1025
1025
|
def change
|
1026
1026
|
add_index :users, :email, unique: true, using: :hash
|
1027
1027
|
end
|
@@ -1033,7 +1033,7 @@ end
|
|
1033
1033
|
Use B-tree indexes instead.
|
1034
1034
|
|
1035
1035
|
```ruby
|
1036
|
-
class AddIndexToUsersOnEmail < ActiveRecord::Migration[7.
|
1036
|
+
class AddIndexToUsersOnEmail < ActiveRecord::Migration[7.2]
|
1037
1037
|
def change
|
1038
1038
|
add_index :users, :email, unique: true # B-tree by default
|
1039
1039
|
end
|
@@ -1048,7 +1048,7 @@ Adding multiple foreign keys in a single migration blocks writes on all involved
|
|
1048
1048
|
Avoid adding foreign key more than once per migration file, unless the source and target tables are identical.
|
1049
1049
|
|
1050
1050
|
```ruby
|
1051
|
-
class CreateUserProjects < ActiveRecord::Migration[7.
|
1051
|
+
class CreateUserProjects < ActiveRecord::Migration[7.2]
|
1052
1052
|
def change
|
1053
1053
|
create_table :user_projects do |t|
|
1054
1054
|
t.belongs_to :user, foreign_key: true
|
@@ -1063,7 +1063,7 @@ end
|
|
1063
1063
|
Add additional foreign keys in separate migration files. See [adding a foreign key](#adding-a-foreign-key) for how to properly add foreign keys.
|
1064
1064
|
|
1065
1065
|
```ruby
|
1066
|
-
class CreateUserProjects < ActiveRecord::Migration[7.
|
1066
|
+
class CreateUserProjects < ActiveRecord::Migration[7.2]
|
1067
1067
|
def change
|
1068
1068
|
create_table :user_projects do |t|
|
1069
1069
|
t.belongs_to :user, foreign_key: true
|
@@ -1072,7 +1072,7 @@ class CreateUserProjects < ActiveRecord::Migration[7.1]
|
|
1072
1072
|
end
|
1073
1073
|
end
|
1074
1074
|
|
1075
|
-
class AddForeignKeyFromUserProjectsToProject < ActiveRecord::Migration[7.
|
1075
|
+
class AddForeignKeyFromUserProjectsToProject < ActiveRecord::Migration[7.2]
|
1076
1076
|
def change
|
1077
1077
|
add_foreign_key :user_projects, :projects
|
1078
1078
|
end
|
@@ -1089,7 +1089,7 @@ Remove all the foreign keys first.
|
|
1089
1089
|
Assuming, `projects` has foreign keys on `users.id` and `repositories.id`:
|
1090
1090
|
|
1091
1091
|
```ruby
|
1092
|
-
class DropProjects < ActiveRecord::Migration[7.
|
1092
|
+
class DropProjects < ActiveRecord::Migration[7.2]
|
1093
1093
|
def change
|
1094
1094
|
drop_table :projects
|
1095
1095
|
end
|
@@ -1101,13 +1101,13 @@ end
|
|
1101
1101
|
Remove all the foreign keys first:
|
1102
1102
|
|
1103
1103
|
```ruby
|
1104
|
-
class RemoveProjectsUserFk < ActiveRecord::Migration[7.
|
1104
|
+
class RemoveProjectsUserFk < ActiveRecord::Migration[7.2]
|
1105
1105
|
def change
|
1106
1106
|
remove_foreign_key :projects, :users
|
1107
1107
|
end
|
1108
1108
|
end
|
1109
1109
|
|
1110
|
-
class RemoveProjectsRepositoryFk < ActiveRecord::Migration[7.
|
1110
|
+
class RemoveProjectsRepositoryFk < ActiveRecord::Migration[7.2]
|
1111
1111
|
def change
|
1112
1112
|
remove_foreign_key :projects, :repositories
|
1113
1113
|
end
|
@@ -1117,7 +1117,7 @@ end
|
|
1117
1117
|
Then remove the table:
|
1118
1118
|
|
1119
1119
|
```ruby
|
1120
|
-
class DropProjects < ActiveRecord::Migration[7.
|
1120
|
+
class DropProjects < ActiveRecord::Migration[7.2]
|
1121
1121
|
def change
|
1122
1122
|
drop_table :projects
|
1123
1123
|
end
|
@@ -1134,7 +1134,7 @@ Otherwise, there's a risk of bugs caused by IDs representable by one type but no
|
|
1134
1134
|
Assuming, there is a `users` table with `bigint` primary key type:
|
1135
1135
|
|
1136
1136
|
```ruby
|
1137
|
-
class AddUserIdToProjects < ActiveRecord::Migration[7.
|
1137
|
+
class AddUserIdToProjects < ActiveRecord::Migration[7.2]
|
1138
1138
|
def change
|
1139
1139
|
add_column :projects, :user_id, :integer
|
1140
1140
|
end
|
@@ -1148,7 +1148,7 @@ Add a reference column of the same type as a referenced primary key.
|
|
1148
1148
|
Assuming, there is a `users` table with `bigint` primary key type:
|
1149
1149
|
|
1150
1150
|
```ruby
|
1151
|
-
class AddUserIdToProjects < ActiveRecord::Migration[7.
|
1151
|
+
class AddUserIdToProjects < ActiveRecord::Migration[7.2]
|
1152
1152
|
def change
|
1153
1153
|
add_column :projects, :user_id, :bigint
|
1154
1154
|
end
|
@@ -1162,7 +1162,7 @@ end
|
|
1162
1162
|
Adding a single table inheritance column might cause errors in old instances of your application.
|
1163
1163
|
|
1164
1164
|
```ruby
|
1165
|
-
class AddTypeToUsers < ActiveRecord::Migration[7.
|
1165
|
+
class AddTypeToUsers < ActiveRecord::Migration[7.2]
|
1166
1166
|
def change
|
1167
1167
|
add_column :users, :string, :type, default: "Member"
|
1168
1168
|
end
|
@@ -1194,7 +1194,7 @@ A safer approach is to:
|
|
1194
1194
|
Active Record < 7 enables partial writes by default, which can cause incorrect values to be inserted when changing the default value of a column.
|
1195
1195
|
|
1196
1196
|
```ruby
|
1197
|
-
class ChangeSomeColumnDefault < ActiveRecord::Migration[7.
|
1197
|
+
class ChangeSomeColumnDefault < ActiveRecord::Migration[7.2]
|
1198
1198
|
def change
|
1199
1199
|
change_column_default :users, :some_column, from: "old", to: "new"
|
1200
1200
|
end
|
@@ -1222,7 +1222,7 @@ config.active_record.partial_inserts = false
|
|
1222
1222
|
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.
|
1223
1223
|
|
1224
1224
|
```ruby
|
1225
|
-
class MySafeMigration < ActiveRecord::Migration[7.
|
1225
|
+
class MySafeMigration < ActiveRecord::Migration[7.2]
|
1226
1226
|
def change
|
1227
1227
|
safety_assured { remove_column :users, :some_column }
|
1228
1228
|
end
|
@@ -78,7 +78,7 @@ You can enqueue your background migration to be run by the scheduler via:
|
|
78
78
|
|
79
79
|
```ruby
|
80
80
|
# db/migrate/xxxxxxxxxxxxxx_enqueue_backfill_project_issues_count.rb
|
81
|
-
class EnqueueBackfillProjectIssuesCount < ActiveRecord::Migration[7.
|
81
|
+
class EnqueueBackfillProjectIssuesCount < ActiveRecord::Migration[7.2]
|
82
82
|
def up
|
83
83
|
enqueue_background_data_migration("BackfillProjectIssuesCount")
|
84
84
|
end
|
data/docs/configuring.md
CHANGED
@@ -156,7 +156,7 @@ This is useful to demystify `online_migrations` inner workings, and to better in
|
|
156
156
|
Consider migration, running on PostgreSQL < 11:
|
157
157
|
|
158
158
|
```ruby
|
159
|
-
class AddAdminToUsers < ActiveRecord::Migration[7.
|
159
|
+
class AddAdminToUsers < ActiveRecord::Migration[7.2]
|
160
160
|
disable_ddl_transaction!
|
161
161
|
|
162
162
|
def change
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class BackgroundSchemaMigrationsChangeUniqueIndex < <%= migration_parent %>
|
2
|
+
def change
|
3
|
+
safety_assured do
|
4
|
+
remove_index :background_schema_migrations, name: :index_background_schema_migrations_on_unique_configuration
|
5
|
+
add_index :background_schema_migrations, [:migration_name, :shard, :connection_class_name], unique: true,
|
6
|
+
name: :index_background_schema_migrations_on_unique_configuration
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -69,7 +69,8 @@ class InstallOnlineMigrations < <%= migration_parent %>
|
|
69
69
|
|
70
70
|
t.foreign_key :background_schema_migrations, column: :parent_id, on_delete: :cascade
|
71
71
|
|
72
|
-
t.index [:migration_name, :shard], unique: true,
|
72
|
+
t.index [:migration_name, :shard, :connection_class_name], unique: true,
|
73
|
+
name: :index_background_schema_migrations_on_unique_configuration
|
73
74
|
end
|
74
75
|
end
|
75
76
|
end
|
@@ -28,6 +28,12 @@ module OnlineMigrations
|
|
28
28
|
migrations << "create_background_schema_migrations"
|
29
29
|
end
|
30
30
|
|
31
|
+
indexes = connection.indexes(BackgroundSchemaMigrations::Migration.table_name)
|
32
|
+
unique_index = indexes.find { |i| i.unique && i.columns.sort == ["connection_class_name", "migration_name", "shard"] }
|
33
|
+
if !unique_index
|
34
|
+
migrations << "background_schema_migrations_change_unique_index"
|
35
|
+
end
|
36
|
+
|
31
37
|
migrations
|
32
38
|
end
|
33
39
|
|
@@ -62,7 +62,7 @@ module OnlineMigrations
|
|
62
62
|
validates :table_name, presence: true, length: { maximum: MAX_IDENTIFIER_LENGTH }
|
63
63
|
validates :definition, presence: true
|
64
64
|
validates :migration_name, presence: true, uniqueness: {
|
65
|
-
scope: :shard,
|
65
|
+
scope: [:connection_class_name, :shard],
|
66
66
|
message: ->(object, data) do
|
67
67
|
message = "(#{data[:value]}) has already been taken."
|
68
68
|
if object.index_addition?
|
@@ -116,6 +116,16 @@ module OnlineMigrations
|
|
116
116
|
end
|
117
117
|
end
|
118
118
|
|
119
|
+
# Whether the migration is considered stuck (is running for some configured time).
|
120
|
+
#
|
121
|
+
def stuck?
|
122
|
+
# Composite migrations are not considered stuck.
|
123
|
+
return false if composite?
|
124
|
+
|
125
|
+
stuck_timeout = (statement_timeout || 1.day) + 10.minutes
|
126
|
+
(enqueued? || running?) && updated_at <= stuck_timeout.seconds.ago
|
127
|
+
end
|
128
|
+
|
119
129
|
# Mark this migration as ready to be processed again.
|
120
130
|
#
|
121
131
|
# This is used to manually retrying failed migrations.
|
@@ -180,7 +190,7 @@ module OnlineMigrations
|
|
180
190
|
if connection.send(:__index_valid?, name, schema: schema)
|
181
191
|
return
|
182
192
|
else
|
183
|
-
connection.remove_index(table_name, name: name)
|
193
|
+
connection.remove_index(table_name, name: name, algorithm: :concurrently)
|
184
194
|
end
|
185
195
|
end
|
186
196
|
end
|
@@ -204,7 +214,7 @@ module OnlineMigrations
|
|
204
214
|
|
205
215
|
def validate_connection_class
|
206
216
|
klass = connection_class_name.safe_constantize
|
207
|
-
if !(klass
|
217
|
+
if !(klass <= ActiveRecord::Base)
|
208
218
|
errors.add(:connection_class_name, "is not an ActiveRecord::Base child class")
|
209
219
|
end
|
210
220
|
end
|
@@ -85,10 +85,15 @@ module OnlineMigrations
|
|
85
85
|
end
|
86
86
|
|
87
87
|
# @private
|
88
|
-
def create_background_schema_migration(migration_name, table_name, **options)
|
89
|
-
options.assert_valid_keys(:definition, :max_attempts, :statement_timeout
|
88
|
+
def create_background_schema_migration(migration_name, table_name, connection_class_name: nil, **options)
|
89
|
+
options.assert_valid_keys(:definition, :max_attempts, :statement_timeout)
|
90
90
|
|
91
|
-
|
91
|
+
if connection_class_name
|
92
|
+
connection_class_name = __normalize_connection_class_name(connection_class_name)
|
93
|
+
end
|
94
|
+
|
95
|
+
Migration.find_or_create_by!(migration_name: migration_name, shard: nil,
|
96
|
+
connection_class_name: connection_class_name) do |migration|
|
92
97
|
migration.assign_attributes(**options, table_name: table_name)
|
93
98
|
|
94
99
|
shards = Utils.shard_names(migration.connection_class)
|
@@ -103,6 +108,17 @@ module OnlineMigrations
|
|
103
108
|
end
|
104
109
|
end
|
105
110
|
end
|
111
|
+
|
112
|
+
private
|
113
|
+
def __normalize_connection_class_name(connection_class_name)
|
114
|
+
if connection_class_name
|
115
|
+
klass = connection_class_name.safe_constantize
|
116
|
+
if klass
|
117
|
+
connection_class = Utils.find_connection_class(klass)
|
118
|
+
connection_class.name if connection_class
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
106
122
|
end
|
107
123
|
end
|
108
124
|
end
|
@@ -68,6 +68,13 @@ module OnlineMigrations
|
|
68
68
|
migration.run
|
69
69
|
end
|
70
70
|
|
71
|
+
# Background schema migrations could take a while to run. It is possible, that the process
|
72
|
+
# never reaches this (or the rescue below) line of code. E.g., when it is force quitted
|
73
|
+
# (SIGKILL etc.) and so the migration will end up in the "running" state and the query is
|
74
|
+
# still executing (or already finished) in the database. This migration can either be safely
|
75
|
+
# manually retried or will be picked up in the future by scheduler when it decides that
|
76
|
+
# this migration is stuck.
|
77
|
+
|
71
78
|
migration.update!(status: :succeeded, finished_at: Time.current)
|
72
79
|
|
73
80
|
ActiveSupport::Notifications.instrument("completed.background_schema_migrations", migration_payload)
|
@@ -29,12 +29,13 @@ module OnlineMigrations
|
|
29
29
|
|
30
30
|
private
|
31
31
|
def find_migration
|
32
|
-
active_migrations = Migration.running.
|
32
|
+
active_migrations = Migration.running.reject(&:stuck?)
|
33
33
|
runnable_migrations = Migration.runnable.enqueued.queue_order.to_a + Migration.retriable.queue_order.to_a
|
34
34
|
|
35
35
|
runnable_migrations.find do |runnable_migration|
|
36
36
|
active_migrations.none? do |active_migration|
|
37
|
-
active_migration.
|
37
|
+
active_migration.connection_class_name == runnable_migration.connection_class_name &&
|
38
|
+
active_migration.shard == runnable_migration.shard &&
|
38
39
|
active_migration.table_name == runnable_migration.table_name
|
39
40
|
end
|
40
41
|
end
|
@@ -179,7 +179,7 @@ module OnlineMigrations
|
|
179
179
|
#
|
180
180
|
def initialize_columns_rename(table_name, old_new_column_hash)
|
181
181
|
transaction do
|
182
|
-
|
182
|
+
__rename_table_and_create_view(table_name, old_new_column_hash)
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
@@ -214,7 +214,9 @@ module OnlineMigrations
|
|
214
214
|
def revert_initialize_columns_rename(table_name, _old_new_column_hash = nil)
|
215
215
|
transaction do
|
216
216
|
execute("DROP VIEW #{quote_table_name(table_name)}")
|
217
|
-
|
217
|
+
|
218
|
+
tmp_table = __tmp_table_name_for_column_rename(table_name)
|
219
|
+
rename_table(tmp_table, table_name)
|
218
220
|
end
|
219
221
|
end
|
220
222
|
|
@@ -241,7 +243,9 @@ module OnlineMigrations
|
|
241
243
|
def finalize_columns_rename(table_name, old_new_column_hash)
|
242
244
|
transaction do
|
243
245
|
execute("DROP VIEW #{quote_table_name(table_name)}")
|
244
|
-
|
246
|
+
|
247
|
+
tmp_table = __tmp_table_name_for_column_rename(table_name)
|
248
|
+
rename_table(tmp_table, table_name)
|
245
249
|
old_new_column_hash.each do |column_name, new_column_name|
|
246
250
|
rename_column(table_name, column_name, new_column_name)
|
247
251
|
end
|
@@ -273,7 +277,7 @@ module OnlineMigrations
|
|
273
277
|
old_new_column_hash.each do |column_name, new_column_name|
|
274
278
|
rename_column(table_name, new_column_name, column_name)
|
275
279
|
end
|
276
|
-
|
280
|
+
__rename_table_and_create_view(table_name, old_new_column_hash)
|
277
281
|
end
|
278
282
|
end
|
279
283
|
|
@@ -906,7 +910,8 @@ module OnlineMigrations
|
|
906
910
|
if renamed_tables.key?(table)
|
907
911
|
super(renamed_tables[table])
|
908
912
|
elsif renamed_columns.key?(table)
|
909
|
-
|
913
|
+
tmp_table = __tmp_table_name_for_column_rename(table)
|
914
|
+
super(tmp_table)
|
910
915
|
else
|
911
916
|
super
|
912
917
|
end
|
@@ -1046,8 +1051,9 @@ module OnlineMigrations
|
|
1046
1051
|
schema ? quote(schema) : "current_schema()"
|
1047
1052
|
end
|
1048
1053
|
|
1049
|
-
def
|
1050
|
-
tmp_table =
|
1054
|
+
def __rename_table_and_create_view(table_name, old_new_column_hash)
|
1055
|
+
tmp_table = __tmp_table_name_for_column_rename(table_name)
|
1056
|
+
|
1051
1057
|
rename_table(table_name, tmp_table)
|
1052
1058
|
column_mapping = old_new_column_hash.map do |column_name, new_column_name|
|
1053
1059
|
"#{quote_column_name(column_name)} AS #{quote_column_name(new_column_name)}"
|
@@ -1059,5 +1065,16 @@ module OnlineMigrations
|
|
1059
1065
|
FROM #{quote_table_name(tmp_table)}
|
1060
1066
|
SQL
|
1061
1067
|
end
|
1068
|
+
|
1069
|
+
def __tmp_table_name_for_column_rename(table_name)
|
1070
|
+
suffix = "_column_rename"
|
1071
|
+
|
1072
|
+
# On ActiveRecord 7.1 can use table_name_length instead of max_identifier_length,
|
1073
|
+
# see https://github.com/rails/rails/pull/45136.
|
1074
|
+
# Also we need to account for "_pkey", because older versions does not correctly rename
|
1075
|
+
# tables with long names. Remove when supporting newer versions only.
|
1076
|
+
prefix_length = max_identifier_length - "_pkey".size - suffix.length
|
1077
|
+
table_name[0, prefix_length] + suffix
|
1078
|
+
end
|
1062
1079
|
end
|
1063
1080
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: online_migrations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.19.
|
4
|
+
version: 0.19.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- fatkodima
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -41,6 +41,7 @@ files:
|
|
41
41
|
- lib/generators/online_migrations/install_generator.rb
|
42
42
|
- lib/generators/online_migrations/templates/add_sharding_to_online_migrations.rb.tt
|
43
43
|
- lib/generators/online_migrations/templates/background_data_migration.rb.tt
|
44
|
+
- lib/generators/online_migrations/templates/background_schema_migrations_change_unique_index.rb.tt
|
44
45
|
- lib/generators/online_migrations/templates/create_background_schema_migrations.rb.tt
|
45
46
|
- lib/generators/online_migrations/templates/initializer.rb.tt
|
46
47
|
- lib/generators/online_migrations/templates/install_migration.rb.tt
|