20

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?

4

5 回答 5

38

由于您只想为所有现有记录设置值,因此可以使用update_all,这比遍历所有订单实例要快得多,因为它仅使用数据库语句并且不实例化所有订单:

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不调用任何验证或触发器。

于 2013-06-30T11:51:08.990 回答
8

我认为最简单的方法是:

  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

然后在控制台中检查它:

>> 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
于 2017-11-25T08:35:12.137 回答
3
def change
  add_column :orders, :payment_type, :string
  Order.all.each do |order|
    order.update_attributes(:payment_type => 'normal')
  end
end
于 2013-06-30T11:19:28.660 回答
2

正如其他人所提到的,依赖将来可能会被删除的类并不是一个好习惯,因为它会在那个时候阻止迁移。

相反,我使用直接执行原始 mySQL:

execute "UPDATE `orders` SET `payment_type` = 'normal'"
于 2018-01-24T08:37:32.963 回答
-1

如果您想通过迁移更新列棒,那么上面的答案很棒, 但是如果您想在自己的机器上本地更新列,以便在共享代码时其他人无法看到更新的属性,只需转到 Rails 控制台并循环...

orders = Order.all

 orders.each do |o|
   o.update_attribute(:payment_type, 'normal')
 end

导轨 4

于 2014-07-09T09:54:04.720 回答