将列类型更改为导轨中较长的字符串

发布于 2024-12-23 16:24:10 字数 378 浏览 1 评论 0 原文

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

在我将应用程序推送到使用 postgres 的 Heroku 后,如果我在内容中的表单中输入长度超过 255 的字符串,我会收到错误

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

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

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

谢谢

At the first migration, I declared on a column content to be string
Activerecord made it to be string(255) according to annotate gem.

After I push the app to heroku, which uses postgres, if I enter in the form in content a string longer than 255 I get the error

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

Problem is I need that content to contain a string that is extremely long perhaps (free text, could be thousands of chars)

  1. What variable (is string is not appropriate for this) would pg accept?
  2. How do I create a migration to replace the type of that column

thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

朦胧时间 2024-12-30 16:24:10

如果您想要一个没有长度限制的字符串,您应该将 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 。您必须在 Rails 中使用 text 来获取 text。在 PostgreSQL 中,text 类型的列和 varchar 类型的列之间没有区别(但是 varchar(n) 不同)。此外,如果您在 PostgreSQL 之上进行部署,则根本没有理由使用 :string (又名 varchar),数据库会处理 text > 和 varchar(n) 内部相同,除了 varchar(n) 的额外长度限制;如果您有外部约束(例如政府表格表明表格 897/B 上的字段 432 将长度为 23 个字符)的列大小。

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

此外,您还应该在同一个数据库(通常是 Heroku 的 PostgreSQL)之上进行开发、测试和部署,甚至应该使用相同版本的数据库服务器。数据库之间还存在其他差异(例如 GROUP BY 的行为),ActiveRecord 不会使您免受这些差异的影响。你可能已经这样做了,但我想我还是要提一下。


更新:较新版本的 ActiveRecord 确实可以无限制地理解 varchar,因此,至少对于 PostgreSQL,您可以说:

change_column :your_table, :your_column, :string, limit: nil

更改 varchar(n) > 列转换为 varchartextvarchar 就 PostgreSQL 而言仍然是同一件事,但某些表单构建器会以不同的方式对待它们:varchar 得到一个 text 则获取多行

You should use text with Rails if you want a string with no length limit. A migration like this:

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

should sort things out. You might want :null => false or some other options on the end of that too.

When you use a string column without an explicit limit, Rails will add an implicit :limit => 255. But if you use text, you'll get whatever arbitrary length string type the database supports. PostgreSQL allows you to use a varchar column without a length but most databases use a separate type for that and Rails doesn't know about varchar without a length. You have to use text in Rails to get a text column in PostgreSQL. There's no difference in PostgreSQL between a column of type text and one of type varchar (but varchar(n) is different). Furthermore, if you're deploying on top of PostgreSQL, there's no reason to use :string (AKA varchar) at all, the database treats text and varchar(n) the same internally except for the extra length constraints for varchar(n); you should only use varchar(n) (AKA :string) if you have an external constraint (such as a government form that says that field 432 on form 897/B will be 23 characters long) on the column size.

As an aside, if you are using a string column anywhere, you should always specify the :limit as a reminder to yourself that there is a limit and you should have a validation in the model to ensure that the limit is not exceeded. If you exceed the limit, PostgreSQL will complain and raise an exception, MySQL will quietly truncate the string or complain (depending on the server configuration), SQLite will let it pass as-is, and other databases will do something else (probably complain).

Also, you should also be developing, testing, and deploying on top of the same database (which will usually be PostgreSQL at Heroku), you should even use the same versions of the database server. There are other differences between databases (such as the behavior of GROUP BY) that ActiveRecord won't insulate you from. You might be doing this already but I thought I'd mention it anyway.


Update: Newer versions of ActiveRecord do understand varchar without a limit so, with PostgreSQL at least, you can say:

change_column :your_table, :your_column, :string, limit: nil

to change a varchar(n) column to varchar. text and varchar are still the same thing as far as PostgreSQL is concerned but some form builders will treat them differently: varchar gets an <input type="text"> whereas text gets a multi-line <textarea>.

2024-12-30 16:24:10

虽然接受的答案非常好,但我想在这里添加一个答案,希望对于像我这样的非专家来说,可以更好地处理原始海报问题第 2 部分。

  • 如何创建迁移来替换该列的类型
  • 生成脚手架迁移

    您可以通过在控制台中键入内容来生成迁移来保存更改(只需将替换为您的表名称,column 表示您的列名称)

    rails generate migration change_table_column
    

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

    例如,我想创建一个迁移,以将名为 TodoItems 的表中的列类型从 string 更改为 text

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

    运行迁移

    输入代码以更改列后,只需运行:

    rake db:migrate
    

    应用迁移。如果您犯了错误,您可以随时使用以下方法恢复更改:

    rake db:rollack
    

    Up 和 Down 方法

    接受的答案引用 UpDown 方法,而不是较新的 Change 方法。自 Rails 3.2 以来,提出了旧式 Up 和 Down 方法与较新的 Change 方法相比有一些优点。 “向上和向下”避免 ActiveRecord::IrreversibleMigration 异常。自 Rails 4 发布以来,您可以使用可逆为了避免这个错误:

    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 :)

    While the accepted answer is excellent, I wanted to add an answer here that hopefully better deals with the original posters question part 2, for non experts like myself.

    1. How do I create a migration to replace the type of that column

    generating scaffold migration

    You can generate a migration to hold your change by typing in your console (just replace the table for your tables name, and column for you column name)

    rails generate migration change_table_column
    

    This will generate skeleton migration inside you Rails application /db/migrate/ folder. This migration is a placeholder for your migration code.

    For example I want to create a migration to change the type of a column from string to text, in a table called TodoItems:

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

    Running your migration

    Once you've entered the code to change the column just run:

    rake db:migrate
    

    To apply your migration. If you make an error you can always revert the change with:

    rake db:rollack
    

    Up and Down methods

    The accepted answer references Up and Down methods, instead of the newer Change method. Since rails 3.2 old style Up and Down Methods presented a few advantages over the newer Change method. 'Up and Down' avoid ActiveRecord::IrreversibleMigration exception. Since the release of Rails 4 you can use reversible to avoid this error:

    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
    

    Enjoy Rails :)

    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文