Reversible migration for change_column_default from not having any default in Rails

Andrew Grimm picture Andrew Grimm · Jul 22, 2015 · Viewed 12k times · Source

The Rails guides to active record migrations says that you can do

change_column_default :products, :approved, from: true, to: false

I've got a change method in Rails that's similar to the following:

change_column_default :people, :height, from: nil, to: 0

with the intention of going from not having any defaults, to having a default of zero.

However, when I try rolling it back, I get

ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration

Considering I give Rails a from and to, why isn't it accepting it?

I'm using Rails 4.2.0.

Answer

Athar picture Athar · Jul 26, 2015

if you are using mysql as adapter, then according to this link http://apidock.com/rails/ActiveRecord/ConnectionAdapters/AbstractMysqlAdapter/change_column_default, your change_column_default migration runs like this

def change_column_default(table_name, column_name, default) #:nodoc:
 column = column_for(table_name, column_name)
 change_column table_name, column_name, column.sql_type, :default => default
end

so as you see it calls change_column within itself when you call change_column_default and according to this link http://edgeguides.rubyonrails.org/active_record_migrations.html change_column migration is irreversible.

This shows why you get ActiveRecord::IrreversibleMigration: ActiveRecord::IrreversibleMigration

So if you want to run migration using change_column_default you have to add def up and def down.

I would suggest to use change_column as it is already been called within change_column_default.

def up
 change_column :people, :height, :integer, default: 0
end

def down
 change_column :people, :height, :integer, default: nil
end