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

我在之前的迁移中创build了一个date列,并将其设置为空。 现在我想改变它是不可空的。 假如数据库中有空行,我该怎么做? 如果他们目前为空,我可以将这些列设置为Time.now。

如果你在迁移中这样做,那么你可以这样做:

# Make sure no null value exist MyModel.update_all({ date_column: Time.now }, { date_column: nil }) # Change the column to not allow null change_column :my_models, :date_column, :datetime, null: false 

在Rails 4中,这是一个更好的解决scheme(DRY):

 change_column_null :my_models, :date_column, false 

要确保该列中没有null值的logging:

 MyModel.update_all({ date_column: Time.now }, { date_column: nil }) 

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

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

更改一个列中的NULL值不允许NULL将导致问题。 这正是在开发环境中能够正常工作的代码types,然后当你尝试将其部署到实际的生产环境时,就会崩溃。 您应该首先将NULL值更改为有效, 然后禁止NULL。 change_column_null中的第四个值就是这个值。 请参阅文档了解更多详情。

此外,我通常更喜欢为该字段设置默认值,所以我不需要每次创build一个新对象时指定该字段的值。 我还包括注释掉的代码来做到这一点。

创build一个具有:default =>值的change_column语句的迁移。

change_column :my_table, :my_column, :integer, :default => 0, :null => false

请参阅: change_column

根据数据库引擎,您可能需要使用change_column_null

Rails 4:

 def change change_column_null(:users, :admin, false ) end 

根据文档 ,在Rails 4.02+中 ,没有像2个参数的update_all一样的方法。 相反,可以使用这个代码:

 # 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 

如果您有现有logging,则不能使用add_timestamps和null:false,所以解决scheme如下:

 def change add_timestamps(:buttons, null: true) Button.find_each { |b| b.update(created_at: Time.zone.now, updated_at: Time.zone.now) } change_column_null(:buttons, :created_at, false) change_column_null(:buttons, :updated_at, false) end