From a979dc4253ad029d03f3e52cce34be1c751d21d9 Mon Sep 17 00:00:00 2001 From: jbranchaud Date: Tue, 18 May 2021 11:57:54 -0500 Subject: [PATCH] Add Replace An Index With A Unique Index as a Rails til --- README.md | 3 +- rails/replace-an-index-with-a-unique-index.md | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 rails/replace-an-index-with-a-unique-index.md diff --git a/README.md b/README.md index a4627cb..6c9af5b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://tinyletter.com/jbranchaud). -_1125 TILs and counting..._ +_1126 TILs and counting..._ --- @@ -721,6 +721,7 @@ _1125 TILs and counting..._ - [Remove The Default Value On A Column](rails/remove-the-default-value-on-a-column.md) - [Render An Alternative ActionMailer Template](rails/render-an-alternative-action-mailer-template.md) - [Render The Response Body In Controller Specs](rails/render-the-response-body-in-controller-specs.md) +- [Replace An Index With A Unique Index](rails/replace-an-index-with-a-unique-index.md) - [Rescue From](rails/rescue-from.md) - [Retrieve An Object If It Exists](rails/retrieve-an-object-if-it-exists.md) - [Rollback A Specific Migration Out Of Order](rails/rollback-a-specific-migration-out-of-order.md) diff --git a/rails/replace-an-index-with-a-unique-index.md b/rails/replace-an-index-with-a-unique-index.md new file mode 100644 index 0000000..33adc5b --- /dev/null +++ b/rails/replace-an-index-with-a-unique-index.md @@ -0,0 +1,34 @@ +# Replace An Index With A Unique Index + +Indexes and uniqueness constraints often go together. In fact, in Postgres, +when you create a unique constraint, an index is created under the hood to +support that constraint. + +What if you already have an index, but you want to turn it into a unique index? +There is no way to alter or update the index to be unique. Instead, what you'll +want to do is drop the index and then recreate it as a unique index. + +Here's how you can do that with the Rails migration DSL: + +```ruby +class ReplaceIndexWithUniqueIndex < ActiveRecord::Migration[5.2] + disable_ddl_transaction! + + def up + remove_index :users_roles, [:user_id, :role_id] + add_index :users_roles, [:user_id, :role_id], unique: true, algorithm: :concurrently + end + + def down + remove_index :users_roles, [:user_id, :role_id] + add_index :users_roles, [:user_id, :role_id], algorithm: :concurrently + end +end +``` + +This removes the original multi-column index and then adds back in a unique +index that covers the same columns. I added `disable_ddl_transactions!` so that +the new index could be added concurrently. + +I've also included a `down` migration that reverses the process in case a +rollback is needed.