Blob Blame History Raw
From d536ffd591d6a2363aaa1ad140f7b450e2e67ac6 Mon Sep 17 00:00:00 2001
From: Jess Bees <jesse@toomanybees.com>
Date: Fri, 29 Oct 2021 15:02:04 -0400
Subject: [PATCH] Raise an exception when using unrecognized options in
 change_table block

In a database migration, the expressions `add_column`, `remove_index`,
etc. accept as keyword options `if_exists: true`/`if_not_exists: true`
which will skip that table alteration if the column or index does or
does not already exist.

This might lead some to think that within a change_table block,
```
change_table(:table) do |t|
	t.column :new_column, if_not_exists: true
	t.remove_index :old_column, if_exists: true
end
```
also works, but it doesn't. Or rather, it is silently ignored when
change_table is called with `bulk: true`, and it works accidentally
otherwise.

This commit raises an exception when these options are used in a
change_table block, which suggests the similar syntax:
`t.column :new_column unless t.column_exists?(:new_column)`. This
suggestion is already made in the documentation to
`ActiveRecord::ConnectionAdapters::Table`.
https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html#method-i-column_exists-3F

Do not raise these new exceptions on migrations before 7.0
---
 .../abstract/schema_definitions.rb            | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index eccb49adb91d8..e88d1637f68c7 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -657,8 +659,8 @@ def index(column_name, **options)
       #  end
       #
       # See {connection.index_exists?}[rdoc-ref:SchemaStatements#index_exists?]
-      def index_exists?(column_name, options = {})
-        @base.index_exists?(name, column_name, options)
+      def index_exists?(column_name, **options)
+        @base.index_exists?(name, column_name, **options)
       end
 
       # Renames the given index on the table.