Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add column to table and fix value for existing records in Rails

I want to add a column called "payment_type" into my "orders" table.

Here is the migration that I have so far:

def change
  add_column :orders, :payment_type, :string
end

I want that payment_type to hold the value "normal" for all the records that currently are in the DB. However, not for the future records. I want no default value for future records. How can I do this?

like image 692
Hommer Smith Avatar asked Jun 30 '13 11:06

Hommer Smith


3 Answers

As you just want to set values for all existing records, you can use update_all, which is much faster than looping over all instances of order, as it uses just database statements and doesn't instanciate all the orders:

class Order < ActiveRecord::Base
end

def up
  add_column :orders, :payment_type, :string
  Order.reset_column_information
  Order.update_all(payment_type: 'normal')
end

def down
  remove_column :orders, :payment_type
end

update_all does not call any validations or triggers.

like image 151
Martin M Avatar answered Oct 18 '22 12:10

Martin M


I think the easiest way to do it:

  class AddStateToSites < ActiveRecord::Migration[5.1]
      def up
        add_column :sites, :state, :string, default: :complete # sets default value for existed records
        change_column :sites, :state, :string, default: nil # changes default value for next
      end

      def down
        remove_column :sites, :state
      end
    end

And after that check it in console:

>> Site.last.state
  Site Load (0.6ms)  SELECT  "sites".* FROM "sites" ORDER BY "sites"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> "complete"
>> Site.new.state
=> nil
like image 28
eugene_trebin Avatar answered Oct 18 '22 10:10

eugene_trebin


def change
  add_column :orders, :payment_type, :string
  Order.all.each do |order|
    order.update_attributes(:payment_type => 'normal')
  end
end
like image 5
Henry Avatar answered Oct 18 '22 12:10

Henry