将列类型更改为Rails中的更长字符串


90

在第一次迁移时,我content根据注释的gem 在列上声明了字符串Activerecord使其为string(255)。

将应用程序推送到使用postgres的heroku后,如果我在表单中输入的内容长度超过255,则出现错误

PGError: ERROR: value too long for type character varying(255)

问题是我需要内容包含一个可能非常长的字符串(自由文本,可能是数千个字符)

  1. pg会接受什么变量(字符串不适合此操作)?
  2. 如何创建迁移以替换该列的类型

谢谢

Answers:


216

text如果您想要一个没有长度限制的字符串,则应该与Rails一起使用。像这样的迁移:

def up
  change_column :your_table, :your_column, :text
end
def down
  # This might cause trouble if you have strings longer
  # than 255 characters.
  change_column :your_table, :your_column, :string
end

应该理清事情。您可能也想要:null => false或其他一些选择。

当您使用string没有显式限制的列时,Rails将添加一个隐式:limit => 255。但是,如果使用text,您将获得数据库支持的任意长度的字符串类型。PostgreSQL允许您使用varchar不带长度的列,但是大多数数据库为此使用单独的类型,而Rails不知道varchar不带长度。您必须text在Rails中使用才能在PostgreSQL中获得一text。有类型的列之间PostgreSQL中没有差异text和类型的一个varchar(但varchar(n) 不同)。此外,如果你对PostgreSQL的顶部部署,没有理由使用:string(AKA varchar)在所有的数据库对待textvarchar(n)内部相同,除了的额外长度限制外varchar(n); 仅当您对列大小有外部约束(例如政府表格说表格897 / B上的字段432的长度为23个字符)时,才应使用varchar(n)(AKA :string)。

顺便说一句,如果您在string任何地方都使用列,则应始终指定:limit,以提醒您存在限制,并且应该在模型中进行验证以确保不超过该限制。如果超出限制,PostgreSQL将抱怨并引发异常,MySQL会悄悄地截断字符串或​​抱怨(取决于服务器配置),SQLite将按原样传递它,而其他数据库将做其他事情(可能抱怨) 。

另外,您还应该在同一数据库(通常是Heroku上的PostgreSQL)上开发,测试和部署,甚至应该使用相同版本的数据库服务器。数据库之间还有其他区别(例如GROUP BY的行为),ActiveRecord不会使您与之隔离。您可能已经在这样做了,但我想还是要提一下。


13
好答案。注意事项:Rails当前不支持使用change方法的change_column(guides.rubyonrails.org/migrations.html#using-the-change-method);如果有足够的内存,那么您将创建一个不可逆的迁移。最好使用上/下方法以传统方式进行操作。
poetmountain 2012年

@BourbonJockey:确实change无法自动撤消类型更改是有意义的,并且《迁移指南》确实说“ [[change method]该方法是编写构造性迁移(添加列或表)的首选方法”,并且change_column是”在您指向的列表中,所以我认为您是对的。我将其修复为使用up/ down(带有警告down),感谢您的注意。
亩太短

4
供其他读者将来参考,以这种方式在Postgres中将字符串从字符串转换为文本不会丢失数据。
Marina Martin

2
@丹尼斯:也许“您应该使用相同的数据库进行开发,测试和部署”会更加准确。通常的问题是,人们使用(荒谬的)Rails默认的SQLite设置,并且当他们部署在其他东西之上时,事情会分崩离析。PostgreSQL仍然是Heroku的默认和最常用的选项,不是吗?
亩太短

3
附带一提,Rails认为未指定长度的字段应为255个字符的假设很奇怪。这是不是在PostgreSQL中需要使用text只是为了获得无限长度; 您可以使用unconstrained varchar。Rails施加了这个奇怪的限制,而不是PostgreSQL。
Craig Ringer 2014年

8

尽管接受的答案非常好,但我想在此处添加一个答案,希望能够更好地处理像我这样的非专家的原始海报问题2。

  1. 如何创建迁移以替换该列的类型

产生支架迁移

您可以通过在控制台中键入来生成迁移以保留您的更改(只需将table表名和column列名替换为即可)

rails generate migration change_table_column

这将在Rails应用程序/ db / migrate /文件夹中生成框架迁移。此迁移是您的迁移代码的占位符。

例如,我想创建一个迁移从改变一个列的类型stringtext,在表中称为TodoItems:

class ChangeTodoItemsDescription < ActiveRecord::Migration
  def change
     # enter code here
     change_column :todo_items, :description, :text
  end
end

运行迁移

输入更改列的代码后,请运行:

rake db:migrate

应用您的迁移。如果发生错误,可以随时通过以下方式还原更改:

rake db:rollack

上下方法

可接受的答案参考UpDown方法,而不是较新的Change方法。由于rails 3.2 旧样式的 Up和Down方法比新的Change方法具有一些优点。“上下”避免ActiveRecord::IrreversibleMigration exception。从Rails 4发行以来,您可以reversible用来避免此错误:

class ChangeProductsPrice < ActiveRecord::Migration
  def change
    reversible do |dir|
      change_table :products do |t|
        dir.up   { t.change :price, :string }
        dir.down { t.change :price, :integer }
      end
    end
  end
end

享受Rails :)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.