尝试将Timestamps添加到现有表中。 根据{{3}}
以下是迁移中的代码:
def change
add_timestamps(:products, null: false)
end
获取错误:
- add_timestamps(:products,{:null => false}) 铁轨中止了! StandardError:发生错误,此以及所有后续迁移都已取消: SQLite3 :: SQLException:无法使用默认值NULL添加NOT NULL列:ALTER TABLE" products" ADD" created_at" datetime NOT NULL
我还尝试了Api documenation add_timestamps
中的所有解决方案同样的错误...... Rails 5.1.4 Ruby 2.4.0
答案 0 :(得分:18)
您不能将具有非空约束的列添加到非空表中,因为表中的现有行会立即具有空值,因此条件失败。
相反,请分三步介绍这些列:
def change
# add new column but allow null values
add_timestamps :products, null: true
# backfill existing record with created_at and updated_at
# values making clear that the records are faked
long_ago = DateTime.new(2000, 1, 1)
Product.update_all(created_at: long_ago, updated_at: long_ago)
# change not null constraints
change_column_null :products, :created_at, false
change_column_null :products, :updated_at, false
end
答案 1 :(得分:2)
我喜欢@spickermann的方法,因为它考虑到了现有记录,并且可能您的迁移已经完全进行了生产,他的方法可以确保数据的持久性。
尽管如此,你们中的许多人可能会在这种情况下找到自己,但仍处于开发阶段,这意味着您可能会害怕丢失真正的敏感数据……这给您更多的自由来执行在表中更改。
如果您的代码和记录仅在本地存在(如果您仍未创建记录,则跳过步骤1。)并且该表是在上一次迁移中创建的,我的建议是:
1.-删除该表中的所有记录。
2.-转到您的迁移文件并通过添加t.timestamps
对其进行编辑,以使其看起来像这样:
class CreateInstitutionalLegals < ActiveRecord::Migration[5.0]
def change
create_table :institutional_legals do |t|
# Your original migration content goes here
.
.
t.timestamps # This is your addition
end
end
end
3.--然后转到控制台并输入rails:db:redo
。如here所述,该命令是执行回滚然后再次迁移回去的快捷方式。
现在,您将看到您的架构已使用相应的created_at
和updated_at
列进行了更新。
这样做的具体好处是它非常容易实现,您无需创建额外的迁移文件,而是学习使用非常方便的命令;)
答案 2 :(得分:2)
我认为,在迁移过程中使用activerecord查询甚至SQL处理现有数据是错误的。
正确的Rails 5.2+方法是:
class AddTimestampsToCars < ActiveRecord::Migration[5.2]
def change
add_timestamps :cars, null: false, default: -> { 'NOW()' }
end
end
这是一个过程,因此您可以根据需要设置过去的日期。
答案 3 :(得分:0)
感谢spicekermann我能够做到这一点
def change
add_timestamps :products, null: true
end
您的解决方案也很好,但为了完整性我们可以在迁移中使用Product类,我们需要将其加载到迁移中,这样做的正确方法是什么? &#34;需要&#34;或其他方法。
答案 4 :(得分:0)
我使用的是Rails 5.0,但这些选项均无效。 rails:db:redo
可以使用,但对于大多数人来说不是可行的解决方案。
唯一起作用的是
def change
add_column :products, :created_at, :timestamp
add_column :products, :updated_at, :timestamp
end
答案 5 :(得分:0)
我遇到了同样的问题。我希望最终结果严格等同于新数据库上的 add_timestamps :products
。
我没有运行查询来回填,而是完成了 3 个步骤。
而且它是可逆的。
add_column :products, :created_at, :datetime, precision: 6, null: true, default: -> { "CURRENT_TIMESTAMP" }
add_column :products, :updated_at, :datetime, precision: 6, null: true, default: -> { "CURRENT_TIMESTAMP" }
change_column_null :products, :created_at, false
change_column_null :products, :updated_at, false
change_column_default :products, :created_at, from: -> { "CURRENT_TIMESTAMP" }, to: nil
change_column_default :products, :updated_at, from: -> { "CURRENT_TIMESTAMP" }, to: nil
注意:这是使用 Rails 6.1 和 PostgreSQL