I created a migration that does two default value updates. It looks something like this:
class ChangeTableNameDefaultValues < ActiveRecord::Migration[7.2]
def change
change_column_default(:table_name, :column_1, from: 'old_default_value', to: 'new_default_value')
change_column_default(:table_name, :column_2, from: 'old_default_value', to: 'new_default_value')
end
end
My linter suggested I wrap this with a change_table bulk: true
statement so I tried it like this:
class ChangeTableNameDefaultValues < ActiveRecord::Migration[7.2]
def change
change_table :table_name, bulk: true do |t|
# Notice here that I don't use the t variable being passed
# to the block. I'm wondering if I need to call a method on t?
change_column_default(:table_name, :column_1, from: 'old_default_value', to: 'new_default_value')
change_column_default(:table_name, :column_2, from: 'old_default_value', to: 'new_default_value')
end
end
end
However, after running the migration, I got the following output:
Migrating to ChangeTableNameDefaultValues (20250221054551)
== 20250221054551 ChangeTableNameDefaultValues: migrating ======================
-- change_table(:table_name, {:bulk=>true})
-- change_column_default(:table_name, :column_1, {:from=>"old_default_value", :to=>"new_default_value"})
TRANSACTION (0.0ms) BEGIN
(2.4ms) ALTER TABLE "table_name" ALTER COLUMN "column_1" SET DEFAULT 'new_default_value'
-> 0.0046s
-- change_column_default(:table_name, :column_2, {:from=>"old_default_value", :to=>"new_default_value"})
(0.5ms) ALTER TABLE "table_name" ALTER COLUMN "column_2" SET DEFAULT 'new_default_value'
-> 0.0017s
-> 0.0072s
== 20250221054551 ChangeTableNameDefaultValues: migrated (0.0072s) =============
So it didn't take advantage of the bulk table updating. I'm wondering if this is possible with changing default values of columns?
The issue is that you need to use change_default
instead of change_column_default
.
change_default
uses the context of the table in the change_table
block, while change_column_default
takes the table as an explicit argument and generates its own statements.
So something like...
def change
change_table :table_name, bulk: true do |t|
# No table needed, already available in context
t.change_default(:column_1, from: 'old_default_value', to: 'new_default_value')
t.change_default(:column_2, from: 'old_default_value', to: 'new_default_value')
end
end
Note that this is NOT reversible.
The list of methods available in change_table
are here.