Rails迁移 – types转换的change_column

我已经google'd一点点,似乎有没有令人满意的答案我的问题。

我有一个stringtypes的列的表。 我想运行以下迁移:

class ChangeColumnToBoolean < ActiveRecord::Migration def up change_column :users, :smoking, :boolean end end 

当我运行这个时,我得到以下错误

 PG::Error: ERROR: column "smoking" cannot be cast automatically to type boolean HINT: Specify a USING expression to perform the conversion. : ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean 

我知道我可以使用纯SQL执行此迁移,但是如果我可以使用Rails来完成,那么仍然会更好。 我经历了Rails代码,似乎没有这种可能性,但也许有人知道一种方式?

我不感兴趣: – 纯SQL – 删除列 – 创build另一列,转换数据,删除原来的,然后重命名

如果smoking列中的string已经是有效的布尔值,则以下语句将更改列types而不会丢失数据:

 change_column :users, :smoking, 'boolean USING CAST(smoking AS boolean)' 

同样,您可以使用此语句将列转换为整数:

 change_column :table_name, :column_name, 'integer USING CAST(column_name AS integer)' 

我正在使用Postgres。 不知道这个解决scheme是否适用于其他数据库。

并不是所有的数据库都允许更改列types,通常采取的方法是添加所需types的新列,将所有数据传入,删除旧列并重命名新列。

 add_column :users, :smoking_tmp, :boolean User.reset_column_information # make the new column available to model methods User.all.each do |user| user.smoking_tmp = user.smoking == 1 ? true : false # If smoking was an int, for example user.save end # OR as an update all call, set a default of false on the new column then update all to true if appropriate. User.where(:smoking => 1).update_all(:smoking_tmp = true) remove_column :users, :smoking rename_column :users, :smoking_tmp, :smoking 

所以在postgres中的布尔值是正确的:

 change_column :table_name, :field,'boolean USING (CASE field WHEN \'your any string as true\' THEN \'t\'::boolean ELSE \'f\'::boolean END)' 

而且你可以在你的表情中添加更多的WHENTHEN条件

对于其他数据库服务器,expression式将基于数据库服务器的语法来构造,但原理是相同的。 只有手动转换algorithm,完全没有SQL,不幸的是不够。

带语法的方法change_column :table, :filed, 'boolean USING CAST(field AS boolean)'只适用于字段内容如下:true / false / null

由于我正在使用Postgres,所以我现在用SQL解决scheme。 使用的查询:

  execute 'ALTER TABLE "users" ALTER COLUMN "smoking" TYPE boolean USING CASE WHEN "flatshare"=\'true\' THEN \'t\'::boolean ELSE \'f\'::boolean END' 

它只适用于一个字段填充了真/假string(比如默认的单选button集合助手,强制布尔types会生成)