Ruby on Rails:如何使用迁移向现有列添加非空约束?

148
在我的Rails(3.2)应用程序中,我有很多数据库表,但我忘记添加一些非空约束。我该如何编写迁移以向现有列添加非空约束?
5个回答

303

您也可以使用change_column_null

change_column_null :table_name, :column_name, false

1
我不得不更改一堆列,这不需要为每个列指定列类型,好多了! - Dorian
1
这是更好的答案。在我的数据库中,我正在对具有现有空值的列添加空值约束。change_column将不会更新那些值。根据文档,change_column_null有一个可选的第四个值,即更新的新值。 - Merovex
谢谢你。最佳答案。 - Ryan Rebo
1
有趣的副作用...回滚迁移将把字段设置为相反的值(false->true)。因此,如果您为多个字段创建迁移以添加空值约束,并且某些字段已经具有空值约束,则回滚迁移将从任何已经具有空值约束的字段中删除该约束。 - jpw
1
第四个选项将为那些列为空的记录设置默认值。但是要小心!如果它是一个大表,可能会导致停机时间。最好先分批回填这些记录,然后再添加没有第四个选项的约束。 - user2992971

97

27
使用这种方法需要小心——如果该列有其他属性(例如:limit限制),在使用change_column时需要重复这些属性,否则它们将会丢失。因此,我更喜欢使用change_column_null - Nathan Wallace
请注意,这会生成一个IrreversibleMigration,这可能不是您想要的。 - Nic Nilov
@NicNilov,你是在谈论答案还是Nathan Wallace的评论? - Mark
@Mark,我在谈论答案,抱歉没有表达得够清楚。 - Nic Nilov
@NicNilov 没事,我只是想再确认一下 :) - Mark

12
  1. 添加默认值列

  2. 删除默认值

add_column :orders, :items, :integer, null: false, default: 0
change_column :orders, :items, :integer, default: nil

2
当您需要添加一个非空列时,正确的解决方案是首先定义它具有默认值,因为SQLLite会抱怨(无法添加具有默认值NULL的NOT NULL列),然后再将其删除! - Milan

3
如果您在新的迁移脚本/模式上使用它,以下是我们如何定义它。
class CreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
    t.string :name, null: false     # Notice here, NOT NULL definition
    t.string :email, null: false
    t.string :password, null: false
    t.integer :created_by
    t.integer :updated_by 

    t.datetime :created_at
    t.datetime :updated_at, default: -> { 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP' }
   end
  end
end

0
在我的方法中,我会向我现有的迁移中需要的列添加NOT NULL约束。之后,我使用以下命令重置所有迁移:

rake db:migrate:reset

这将删除数据库,重新创建它并运行所有迁移。您可以在schema.rb中检查更改。
如果您的简单迁移中只有几列,您可以使用此方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接