Rails改变列类型并更新列值[英] Rails change column type and update column values

本文是小编为大家收集整理的关于Rails改变列类型并更新列值的处理方法,想解了Rails改变列类型并更新列值的问题怎么解决?Rails改变列类型并更新列值问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我有一个名为 Users 的表,其中包含一个类型为布尔值的 Active 列.我很快需要将该列的类型更改为字符串.我还需要将 Active 的所有列值从 :true 更改为"active",将 :false 更改为"inactive".

要更改我将使用的列类型在 ROR 迁移期间将列类型从 Date 更改为 DateTime

class ChangeColumnTypeInUsers < ActiveRecord::Migration
  def up
    change_column :users, :active, :string
  end

  def down
    change_column :users, :active, :boolean
  end
end

我将如何更新列值以便类型更改不会破坏它?它会自动将 :true 转换为"true"吗?

推荐答案

您可以使用 ALTER TABLE 的使用子句:

<块引用>

可选的 USING 子句指定如何从旧的列值计算新的列值;如果省略,则默认转换与从旧数据类型转换为新数据类型的赋值相同.

一个简单的 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 式 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 作为列类型.当您无限制地说 :string 时,Rails 将在数据库中使用 varchar(255),这对 PostgreSQL 毫无意义,因为它处理所有字符串类型的存储 内部几乎相同,char(n) 和varchar(n) 的长度限制实际上使它们比text 使用起来更昂贵.那么只有 :string 对 PostgreSQL 有意义的时候是当你有理由包含一个特定的 :limit (然后一个 text 列对长度有 CHECK 约束会更有意义,但 AR 太愚蠢了了解诸如 CHECK 约束之类的"高级"事物).

其他推荐答案

让您的迁移完美无缺的一种简单方法是重命名您的布尔值 :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

其他推荐答案

我没有做过,但我认为这只是在你的 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.应该管用.我刚刚在我的数据库中的单个用户的控制台中对其进行了测试,所以看起来不错.

本文地址:https://www.itbaoku.cn/post/1763799.html