Here’s a big fat TIL. The Rails change method can add a column back, including it’s original data type, if you tell it to. I know this works in Rails 6. I’m not sure about other versions.

TL;DR

Do this:

rails g migration RemoveIsCoolFromUsers, is_cool

Get this:

class RemoveIsCoolFromUsers < ActiveRecord::Migration
  # on up: removes the column
  # on down: adds the column back as the boolean data type
  def change
    remove_column :users, :is_cool, :boolean
  end
end

The Longer Version

Here’s the scenario. We have a users table and we don’t need the is_cool column anymore, so we plan to drop it.

# users table

users
-----
is_cool: boolean <-- don't need this anymore
email: string
full_name: string

Normally, I’d generate a migration like this:

rails g migration RemoveIsCoolFromUsers

I’d get a migration file that looks like this:

class RemoveIsCoolFromUsers < ActiveRecord::Migration
  def change
  end
end

and then I’d fill it in like this:

class RemoveIsCoolFromUsers < ActiveRecord::Migration
  def change
    remove_column :users, :is_cool
  end
end

Since I’m doing a destructive migration by removing a column, I want to ensure a successful rollback (adding the column back in again) by being explicit about this column being a boolean data type as it was before. To do that, I normally break that change method up into the 2 older syntax methods: up and down.

class RemoveIsCoolFromUsers < ActiveRecord::Migration
  # runs when we call rake db:migrate
  def up
    remove_column :users, :is_cool
  end

  # runs when we call rake db:rollback
  def down
    add_column :users, :is_cool, :boolean
  end
end

As it turns out, I’ve been doing it the long way this whole time. Jeeze Louise. Now here’s the magic: change knows how to do all of this for you if you pass it the column name and data type like this:

rails g migration RemoveIsCoolFromUsers, is_cool:boolean

which gives you this in the migration file:

class RemoveIsCoolFromUsers < ActiveRecord::Migration
  # on up: removes the column
  # on down: adds the column back as the boolean data type
  def change
    remove_column :users, :is_cool, :boolean
  end
end

Now change will know to add this column back as a boolean data type! That is pretty neato. Now, if my migrations are any more complicated than simply removing a single column, I still see myself wanting to have the explicit up and down actions lined out. That decision isn’t so much about being an old dog as it is about not quite understanding the limitations of this new trick just yet.

FYI: Deleting columns will cause data loss

Also, please note, if you delete a column and add it back, you will lose your data. So ya know, always be sure you want to delete a column before you do so. In fact, if you use the strong_migrations gem, you will be prompted to ignore a column before you can remove it. You can read more about that on the strong_migrations github page.