Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reversible migration for change_column_default from not having any default in Rails

Tags:

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.

like image 574
Andrew Grimm Avatar asked Jul 22 '15 01:07

Andrew Grimm


People also ask

How do I rollback a migration in Rails?

To check for status, run rails db:migrate:status . Then you'll have a good view of the migrations you want to remove. Then, run rails db:rollback to revert the changes one by one. After doing so, you can check the status again to be fully confident.

How do I run a specific migration in Rails?

To run a specific migration up or down, use db:migrate:up or db:migrate:down . The version number in the above commands is the numeric prefix in the migration's filename. For example, to migrate to the migration 20160515085959_add_name_to_users. rb , you would use 20160515085959 as the version number.


2 Answers

Using from and to was added in Rails 5+

The guide linked to in the question is for Edge Rails, not for a released version of Rails.

Reversible syntax for change_column_default is the result of pull request 20018. The pull request also updated the Rails guides for Edge Rails.

From activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb:

-      def change_column_default(table_name, column_name, default)
+      # Passing a hash containing +:from+ and +:to+ will make this change
+      # reversible in migration:
+      #
+      #   change_column_default(:posts, :state, from: nil, to: "draft")
+      #
+      def change_column_default(table_name, column_name, default_or_changes)

The pull request was made June 27, 2015, which is more recent than any version of Rails released as of August 1, 2015.

The documentation for migration for Rails 4.2.3 reflects the fact that reversible syntax is not yet available:

change_column_default :products, :approved, false
like image 154
Andrew Grimm Avatar answered Sep 25 '22 14:09

Andrew Grimm


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
like image 31
Athar Avatar answered Sep 24 '22 14:09

Athar