问题描述
我必须向现有表添加 2 个新列,它们是 created_at
、updated_at
。但是,created_at
和 updated_at
字段不应为空,除非我的数据库中有几条现有记录,因此简单的 change
迁移不起作用。我决定进行向上/向下迁移,因为我需要先更新这些记录,然后再将这些字段设置为 not null
。
我的迁移文件如下所示:
Class AddColumnstocharge < ActiveRecord::Migration[6.0]
def up
add_column :charges,:created_at,:datetime
add_column :charges,:updated_at,:datetime
Charge.update_all(created_at: Time.Now,updated_at: Time.Now)
end
def down
change_column :charges,:datetime,null:false
change_column :charges,null:false
end
end
现在这似乎有效,因为我不再收到错误,抱怨现有列的 created_at
/updated_at
字段为空值。但是我的 schema.rb 没有将这些字段显示为 null: false
而是我看到
create_table "charges",force: :cascade do |t|
t.bigint 'amount'
t.datetime 'created_at'
t.datetime 'updated_at'
我希望看到的是:
create_table "charges",force: :cascade do |t|
t.bigint 'amount'
t.datetime 'created_at',null: false
t.datetime 'updated_at',null: false
是我的 down 没有被执行还是我在迁移文件中做错了什么?(提前感谢您的帮助)
解决方法
down
在您运行 rails db:rollback
时使用,这是您尝试做的吗?
up
在运行 rails db:migrate
时使用。通常 Rails 知道如何使用 change
在迁移中就足够了,但有时您需要使用 up/down
以便迁移是可逆的。
来自docs
您也可以使用 up 和 down 方法使用旧式迁移 而不是更改方法。 up 方法应该描述 您想要对架构进行的转换,以及 down 方法 您的迁移应该恢复由 up 完成的转换 方法。换句话说,数据库架构应该保持不变,如果你 先上后下。例如,如果您在 up 方法,你应该把它放在 down 方法中。
,你需要这个:
class AddTimestamps < ActiveRecord::Migration[6.1]
def change
reversible do |dir|
change_table :charges do |t|
dir.up do
t.timestamps
Charge.update_all(created_at: Time.now,updated_at: Time.now)
end
dir.down do
remove_column :charges,:created_at
remove_column :charges,:updated_at
end
end
end
end
end
created_at
和 updated_at
的默认值未反映在架构 b/c 中,它始终由 ActiveRecord 填充,它们没有数据库配置的默认值。分配的值是动态的,您只能在架构中放置固定的默认值。
当您使用 null: false
方法指定 created_at
时,会自动添加 timestamps
(Rails 5 以后)。当您显式创建/删除 created_at/updated_at 列时,不会自动添加该选项。
在我看来,您正在寻找类似的东西。
add_column :charges,:created_at,:datetime
add_column :charges,:updated_at,:datetime
change_column_null(:charges,false,Time.now)
change_column_null(:charges,Time.now)
,
通过运行两个不同的迁移,我能够长期解决我的问题。
我的第一次迁移添加了新列:
Class AddColumnsToCharge < ActiveRecord::Migration[6.0]
def change
add_column :charges,:datetime
add_column :charges,:datetime
end
end
在运行第二次迁移之前,我进入了 rails 控制台并更新了当前记录:Charge.update_all(created_at: Time.now,updated_at: Time.now)
第二次迁移:
Class AddColumnsToCharge < ActiveRecord::Migration[6.0]
def change
change_column :charges,:datetime,null:false
change_column :charges,null:false
end
end
这个答案没有回答最初的问题,而是完成了我最终想要的工作。