Rails更改列类型并更新列值

Mic*_*Fin 6 postgresql activerecord ruby-on-rails ruby-on-rails-4 rails-activerecord

我有一个名为Users的表,其活动列为boolean。我很快将需要将该列的类型更改为字符串。我还需要将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
Run Code Online (Sandbox Code Playgroud)

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

mu *_*ort 5

您可以使用ALTER TABLEUSING子句轻松地完成此操作:

可选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
))
Run Code Online (Sandbox Code Playgroud)

对您来说重要的部分是最后的using case ...部分。您可以change_column通过诱使AR进行“正确的事情” 来将其与常见的AR-ish 东西结合使用:

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
Run Code Online (Sandbox Code Playgroud)

请注意,我使用的text是列类型。Rails会使用varchar(255)数据库里面,当你说:string没有限制,因为它可以为所有字符串类型的存储这是PostgreSQL的漂亮毫无意义几乎相同的内部,在长度的限制char(n),并varchar(n)实际上使它们比使用更昂贵text。然后,只有时间:string对PostgreSQL有意义,您才有理由包括一个特定的对象:limit(然后,对长度进行约束的textCHECK会更有意义,但是AR太愚蠢,无法了解诸如CHECK约束之类的“高级”东西)。