通过迁移将默认值添加到列


276

如何将默认值添加到通过迁移已存在的列中?

我可以找到的所有文档都向您展示了如果该列不存在但该情况下该如何做的方法。

Answers:


352

这是您应该如何做:

change_column :users, :admin, :boolean, :default => false

但是某些数据库(例如PostgreSQL)不会更新以前创建的行的字段,因此请确保在迁移时也手动更新该字段。


14
如果您需要可逆迁移,则将其放在一个up块而不是一个change块中。您可以将down块保留为空。它不会将表恢复为原始状态,但可以回滚迁移。
IAmNaN 2014年

1
这样可以保持数据完整吗?
Marco Prins

2
在PostgreSQL上,是的,我不知道其他数据库会发生什么。
毛里西奥利尼亚雷斯

1
说“确保在迁移时手动更新字段”是什么意思?如何做到这一点?
David Argyle Thacker,

7
我在PostgreSQL上尝试过,它更新了以前创建的字段。
Aboozar Rajabi

190
change_column_default :employees, :foreign, false

1
@DenisLins我同意您的意见,所以我进行了一些研究来弄清楚为什么可能不支持它,事实证明特定的数据库适配器可能不支持它,因为它是在该级别实现的。除非在抽象模型中实现,否则可接受的答案仍然是最安全的选择。 apidock.com/rails/ActiveRecord/ConnectionAdapters/...
natchiketa

5
除此之外,您还需要指定a from:to:如果您希望它是可逆的:)
radubogdan

5
在此提交中,在Rails 5+中使用fromto进行了添加:github.com/rails/rails/pull/20018/files
Joshua Pinter

114

对于Rails 4+,请使用change_column_default

def change
  change_column_default :table, :column, value
end

1
如果您要进行的迁移是添加一列并为现有记录设置默认值,那么这特别好。例如: def change `add_column:foos,:name,默认值:“现有值之物”``change_column_default:foos,:name,默认值:“”`end
user1491929

2
这种迁移具有奇怪的行为。在您的示例中,这是不可逆的。edgeguides.rubyonrails.org/active_record_migrations.html建议以这种方式使用它:change_column_default :products, :approved, from: true, to: false—但它也不起作用。
Ilya Krigouzov '16

无法回滚使用?
aldrien.h 18-2-27

通常,是的,对于几乎所有的“ Change”子句来说,因为以前的所有状态通常都是显式的,例如列的存在,类型等。可以且仅当存在一个以前有效的显式默认值。由于通常未定义默认值,因此您可能会遇到问题。
Elindor

48

使用def change意味着您应该编写可逆的迁移。并且change_column是不可逆的。您可以上升,但不能下降,因为这change_column是不可逆的。

相反,尽管可能会多出几行,但您应该使用def updef down

因此,如果您有没有默认值的列,那么您应该这样做以添加默认值。

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: nil
end

或者,如果您想更改现有列的默认值。

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: true
end

37

** Rails 4.X + **

从Rails 4开始,您无法生成将列添加到具有默认值的表的迁移, 以下步骤将新列添加到具有默认值true或false的现有表。

1.从命令行运行迁移以添加新列

$ rails generate migration add_columnname_to_tablename columnname:boolean

上面的命令将在表中添加一个新列。

2.通过编辑创建的新迁移文件,将新列值设置为TRUE / FALSE。

class AddColumnnameToTablename < ActiveRecord::Migration
  def change
    add_column :table_name, :column_name, :boolean, default: false
  end
end

** 3。要对您的应用程序数据库表进行更改,请在终端中运行以下命令**

$ rake db:migrate

这与rails 3+或2+有什么不同?
Ruby Racer

2
有人知道这是否已合并到Rails 5中吗?
sambecker's

9

执行:

rails generate migration add_column_to_table column:boolean

它将生成此迁移:

class AddColumnToTable < ActiveRecord::Migration
  def change
    add_column :table, :column, :boolean
  end
end

设置默认值::default => 1

add_column:table,:column,:boolean,:default => 1

跑:

耙db:migrate


2
现在默认值1并不完全是布尔值;)另外,此示例添加了一个新列,而不是更改现有列,这是OP想要实现的目标
radiospiel

@radiospiel实际上,1也是一个布尔值:)
kinduff

您还需要在外键表中创建一个ID为1的记录,才能避免此记录Key is not present in table error
Promise Preston

-50

您可以执行以下操作:

class Profile < ActiveRecord::Base
  before_save :set_default_val

  def set_default_val
    self.send_updates = 'val' unless self.send_updates
  end
end

编辑:...但是显然这是菜鸟的错误!


最好在架构中设置默认值,而不是将其设置为before_save
rigelstpierre

6
多么可怕的建议
svelandiag

同意,这真的很糟糕
侯城

3
哎呀,在模型级别而不是数据库级别执行某项操作会带来很多麻烦。-38是一个传奇的成绩。
nurettin

1
什么菜鸟错误... ;-)
webaholik
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.