【问题标题】:Using postgres ENUM with rails yields `PG::DatatypeMismatch`将 postgres ENUM 与 rails 一起使用会产生 `PG::DatatypeMismatch`
【发布时间】:2016-06-29 22:13:24
【问题描述】:

尝试更新 Postgres ENUM 列的值会引发以下异常:

ActiveRecord::StatementInvalid Exception: PG::DatatypeMismatch: ERROR: column "interesting_column" 的类型是interesting_thing,但表达式的类型是整数

第 1 行:UPDATE "interesting_table" SET "interesting_column" = 0, "updated_a...

提示:您需要重写或强制转换表达式。

InterestingTable.first.update_attributes!(normal_column: 'food')
  # => perfectly fine
InterestingTable.first.update_attributes!(interesting_column: 'foo')
  # => above exception

这里是创建表的迁移:

class CreateInterestingTables < ActiveRecord::Migration
  def up
    execute <<-SQL
      CREATE TYPE normal_thing AS ENUM ('food', 'water', 'shelter');
      CREATE TYPE interesting_thing AS ENUM ('foo', 'bar', 'baz');
    SQL

    create_table :interesting_tables do |t|
      t.column :normal_column, :normal_thing
      t.column :interesting_column, :interesting_thing
    end
  end

  def down
    drop_table :interesting_tables
    execute 'DROP TYPE normal_thing'
    execute 'DROP TYPE interesting_thing'
  end
end

【问题讨论】:

    标签: ruby-on-rails postgresql ruby-on-rails-3 ruby-on-rails-4 enums


    【解决方案1】:

    问题在于,虽然该列在数据库中具有正确的类型,但活动记录会尝试将其解释为integer。您可以通过运行来验证:

    InterestingTable.columns
    # => [#<ActiveRecord::ConnectionAdapters::PostgreSQLColumn:0x007f7567f82260
    #      @coder=nil,
    #      @default=nil,
    #      @limit=nil,
    #      @name="id",
    #      @null=false,
    #      @precision=nil,
    #      @primary=true,
    #      @scale=nil,
    #      @sql_type="integer",
    #      @type=:integer>,
    #     #<ActiveRecord::ConnectionAdapters::PostgreSQLColumn:0x007f7568075690
    #      @coder=nil,
    #      @default=nil,
    #      @limit=nil,
    #      @name="normal_column",
    #      @null=true,
    #      @precision=nil,
    #      @primary=false,
    #      @scale=nil,
    #      @sql_type="normal_thing",
    #      @type=nil>,
    #     #<ActiveRecord::ConnectionAdapters::PostgreSQLColumn:0x007f7568075668
    #      @coder=nil,
    #      @default=nil,
    #      @limit=nil,
    #      @name="interesting_column",
    #      @null=true,
    #      @precision=nil,
    #      @primary=false,
    #      @scale=nil,
    #      @sql_type="interesting_thing",
    #      @type=:integer>]
    

    注意第二列的类型是nil,而最后一列的类型是integer。如果您的字符串不是以数字开头,String#to_i 返回 0,因此您会收到尝试分配 0 的错误。


    但这是为什么呢?原因 - interesting_thing 包含子字符串 int,适配器将其视为 integer。这似乎是一个长期存在的错误,直到 rails 4.2 才修复。 The offending method.


    可能的解决方案:

    • 迁移到 Rails 4.2+
    • 将您的 ENUM 重命名为不匹配的名称
    • Monkey 修补适配器。这是quick fix

    【讨论】:

      猜你喜欢
      • 2014-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-31
      • 2012-12-24
      • 2020-04-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多