Rails migrations: self.up and self.down versus change

Ruby on-RailsMigrationRails ActiverecordRails Migrations

Ruby on-Rails Problem Overview


Looks like the new rails version has "change" versus self.up and self.down methods.

So what happens when one has to roll back a migration how does it know what actions to perform. I have the following method that I need to implement based on an online tutorial:

class AddImageToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :image_file_name, :string
    add_column :users, :image_content_type, :string
    add_column :users, :image_file_size, :integer
    add_column :users, :image_updated_at, :datetime
  end

  def self.down
    remove_column :users, :image_file_name, :string
    remove_column :users, :image_content_type, :string
    remove_column :users, :image_file_size, :integer
    remove_column :users, :image_updated_at, :datetime
  end    
end

How can I do the same using the new change method?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

For many operations rails can guess what is the inverse operation (without problems). For example, in your case what is the reverse operation of add_column to call when you rollback? Of course it's remove_column. What is the inverse of create_table? It's drop_table. So in these cases rails know how to rollback and define a down method is superfluous (you can see in the documentation the methods currently supported from the change method).

But pay attention because for some kind of operation you still need to define the down method, for example if you change the precision of a decimal column how to guess the original precision on rollback? It's not possible, so you need to define the down method.

As said, I suggest you to read the Rails Migrations Guide.

Solution 2 - Ruby on-Rails

Better to use Up, Down, Change:

On Rails 3 (Reversible): which should add new column on up and fill all records in table only on up, and only delete this column on down

def up
  add_column :users, :location, :string
  User.update_all(location: 'Minsk')
end

def down
  remove_column :users, :location
end

But:

You had to avoid using change method which allows to save some time. For example, if you didn’t need to update column value immediately after it’s adding you would cut this code down to like this:

def change
  add_column :users, :location, :string
end

On up it will add column to table and remove it on down. Much less code and it’s a profit.

On Rails 4: one more useful way to write what we need in one place:

def change
  add_column :users, :location, :string
  reversible do |direction|
    direction.up { User.update_all(location: 'Minsk') }
  end
end

Solution 3 - Ruby on-Rails

class AddImageToUsers < ActiveRecord::Migration
  def change
    add_column :users, :image_file_name, :string
    add_column :users, :image_content_type, :string
    add_column :users, :image_file_size, :integer
    add_column :users, :image_updated_at, :datetime
  end
end

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbanditKingView Question on Stackoverflow
Solution 1 - Ruby on-RailsAldo 'xoen' GiambellucaView Answer on Stackoverflow
Solution 2 - Ruby on-RailsKaleem UllahView Answer on Stackoverflow
Solution 3 - Ruby on-Railsnothing-special-hereView Answer on Stackoverflow