我有一个名为Users的表,其列为Active,类型为boolean。我很快就需要将该列的类型更改为字符串。我还需要将Active的所有列值更改为:true到" active"和:false到"不活动"。
要更改我要使用的列类型 Change a column type from Date to DateTime during ROR migration
class ChangeColumnTypeInUsers < ActiveRecord::Migration
def up
change_column :users, :active, :string
end
def down
change_column :users, :active, :boolean
end
end
如何更新列值以便类型更改不会破坏它?它会自动转换:true到&#34; true&#34;?
答案 0 :(得分:3)
使您的迁移完美无缺的简单方法是重命名您的boolean:active列。添加新列。运行SQL更新,然后删除未使用的列。所有这些都可以在同一次迁移中完成。像这样。不包括向下迁移,所以使用你自己的危险:)。
class ChangeColumnTypeInUsers < ActiveRecord::Migration
def up
rename_column :users, :active, :active_boolean
add_column :users, :active, :string
execute "UPDATE users SET active = 'true' WHERE active_boolean = true"
execute "UPDATE users SET active = 'inactive' WHERE active_boolean = false"
remove_column :users, :active_boolean
end
end
答案 1 :(得分:3)
使用USING clause of ALTER TABLE:
,您可以轻松地一次完成可选的
USING
子句指定如何从旧的计算新列值;如果省略,则默认转换与从旧数据类型转换为new的赋值相同。
简单的SQL类型转换将为您留下字符串'true'
和'false'
,因此您确实需要添加USING。我绕过AR并手动完成:
connection.execute(%q(
alter table users
alter column active
type text
using case when active then 'active' else 'inactive' end
))
最重要的部分是using case ...
部分。通过欺骗AR做正确的事情,你可以将它与通常的AR-ish change_column
一起使用:
class ChangeColumnTypeInUsers < ActiveRecord::Migration
def up
change_column :users, :active, "text using case when active then 'active' else 'inactive' end"
end
def down
change_column :users, :active, "boolean using active = 'active'"
end
end
请注意,我使用text
作为列类型。当你说varchar(255)
没有限制时,Rails会在数据库中使用:string
,这对于PostgreSQL来说是非常没有意义的,因为它处理所有字符串类型pretty much the same internally的存储空间,长度对char(n)
和varchar(n)
的限制实际上使其使用起来比text
更昂贵。那么只有时间:string
对PostgreSQL有意义,当你有理由包含一个特定的:limit
时(然后text
列的长度会CHECK
约束感觉更有意义,但AR太愚蠢了,无法了解&#34;高级&#34;像CHECK
约束这样的事情。
答案 2 :(得分:0)
我还没有这样做,但我认为它只是在您的up方法中添加更多内容或编写单独的迁移来处理up部分。这样......
class ChangeColumnTypeInUsers < ActiveRecord::Migration
def up
change_column :users, :active, :string
User.find_each do |user|
user.active = "active" if user.active = true
user.save!
end
end
def down
change_column :users, :active, :boolean
end
end
你也可以把它变成if / else来处理false。应该管用。我只是在我的数据库中的单个用户的控制台中测试它,所以看起来很好。