如何在Rails迁移中将可空列更改为不可为空?

Kev*_*ang 181 migration ruby-on-rails

我在之前的迁移中创建了一个日期列,并将其设置为可为空.现在我想把它改成不可空.假设该数据库中有空行,我该怎么做呢?如果它们当前为空,我可以将这些列设置为Time.now.

Dan*_*nne 192

如果你在迁移中执行它,那么你可能会这样做:

# Make sure no null value exist
MyModel.where(date_column: nil).update_all(date_column: Time.now)

# Change the column to not allow null
change_column :my_models, :date_column, :datetime, null: false
Run Code Online (Sandbox Code Playgroud)

  • change方法不太适合这种情况,因为(1)update_all方法将同时在迁移和潜在还原上执行。那可能不是最坏的事情,而是因为(2)迁移无法得知潜在还原中列的更改。因此,在这种情况下,我会坚持使用“向上”和“向下”。 (2认同)
  • 您永远不应该使用模态本身在迁移中进行数据更改。例如,您可能会在以后的迁移中删除模型(在本例中为 MyModel)。如果有人然后运行您的所有迁移,它就会中断。而是直接使用 ActiveRecord::Base.connection.execute('your sql here') 执行 SQL 语句 (2认同)
  • 对于任何感兴趣的人,[我的回答](http://stackoverflow.com/a/25211732/616644) 展示了如何一步完成。 (2认同)

mrb*_*rdo 150

在Rails 4中,这是一个更好的(DRYer)解决方案:

change_column_null :my_models, :date_column, false
Run Code Online (Sandbox Code Playgroud)

要确保NULL该列中没有包含值的记录,您可以传递第四个参数,该参数是用于具有NULL值的记录的默认值:

change_column_null :my_models, :date_column, false, Time.now
Run Code Online (Sandbox Code Playgroud)

  • 也可用于3.2.还有第4个参数用于设置默认值,其中value为null. (5认同)
  • 当表已具有空值时,这会导致问题.[见我的回答](http://stackoverflow.com/a/25211732/616644) (4认同)
  • 实际上,根据Rails 4.2文档,第4个参数不会为将来的记录设置默认值:"该方法接受一个可选的第四个参数来用现有的+ NULL + s替换其他值.请注意第四个参数未设置列的默认值." (2认同)

Ric*_*ith 66

Rails 4(其他Rails 4答案有问题):

def change
  change_column_null(:users, :admin, false, <put a default value here> )
  # change_column(:users, :admin, :string, :default => "")
end
Run Code Online (Sandbox Code Playgroud)

更改其中包含NULL值的列不允许NULL将导致问题.这正是在开发设置中可以正常工作的代码类型,然后在您尝试将其部署到LIVE生产时崩溃.您应该首先将NULL值更改为有效的值,然后禁止NULL.第四个值change_column_null就是这样.有关详细信息,请参阅文档

另外,我通常更喜欢为字段设置默认值,因此每次创建新对象时都不需要指定字段的值.我还包括注释掉的代码.

  • 如果要向表中添加新列并希望为null插入新值,但又不想为列添加默认值,则可以在迁移中执行此操作:`add_column:users,:admin,: string` then`change_column_null(:admin,:string,false,"new_value_for_existing_records")` (4认同)
  • 对于Rails 4,这似乎是最准确和完整的答案,包括已注释掉的默认设置. (3认同)

jes*_*rry 33

创建具有值的change_column语句的迁移:default =>.

change_column_null

请参阅:change_column

您可能需要使用数据库引擎 change_column

  • @rtfminc我强烈建议您在开发和生产中使用相同的数据库引擎,因为它避免了边缘情况下的许多问题. (3认同)

pir*_*ast 11

导轨4:

def change
  change_column_null(:users, :admin, false )
end
Run Code Online (Sandbox Code Playgroud)