如何在Rails 3中的Postgres数据库中使用枚举?

时间:2011-09-07 16:34:18

标签: ruby-on-rails ruby-on-rails-3 postgresql enums database-migration

PostgreSQL在数据库中内置了enumerated types的概念。

如何实现一个包含在Rails 3中使用枚举类型的列的表?你需要以某种方式在PostgreSQL中定义枚举吗?你怎么能创建一个这样做的数据库迁移?

使用Rails 3.07,Ruby 1.92p180,PostgreSQL 8.3。

3 个答案:

答案 0 :(得分:13)

Rails不支持开箱即用的ENUM数据类型。这是因为并非所有数据库都支持该数据类型。我发现处理ENUM值的常用方法是在数据库中手动创建枚举列(在您的情况下为PostgreSQL),并在Rails应用程序中将其作为string列处理。然后,使用validates_inclusion_of验证程序强制使用允许的值。

validates_inclusion_of :gender, :in => [ "male", "female" ]

在迁移中使用本机SQL添加枚举字段:

class AddEnumType < ActiveRecord::Migration
  def up
    execute ".." # your native PostgreSQL queries to add the ENUM field
  end
end

编辑(2014年6月)

Rails 4.1现在supports enumsvalidates_inclusion_of现在可以更改为:

enum gender: [ :male, :female ]

(但是,底层数据库本身仍然不支持此功能,因此仍需要本机SQL迁移。)

答案 1 :(得分:9)

您还可以将架构设置为使用原始SQL而不是.rb文件。如果您正在利用数据库的更高级功能(枚举,全文搜索,触发器,函数等),而不是简单地将其用作通用数据存储,这将使您的生活更轻松。

只需在config / application.rb中设置此行

即可
# Use SQL for the schema due to many database specific settings
config.active_record.schema_format = :sql

它将输出一个可以解决该问题的structure.sql文件。

答案 2 :(得分:3)

除了上述答案,对于Rails 4(可能还有3.2),您可以这样做以避免“无效OID”类型警告:

ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID.alias_type 'my_enum_type', 'text'

查询时,您还需要将字符串转换为您的类型,例如

scope :my_enum_value_is, ->(value){ 
  where('my_enum_value = ?::my_enum_type', value) 
}

您还需要修补列解析器:

class ActiveRecord::ConnectionAdapters::Column
  private
  def simplified_type_with_my_enum_type(field_type)
    if field_type == 'my_enum_type'
      field_type.to_sym
    else
      simplified_type_without_my_enum_type(field_type)
    end
  end
  alias_method_chain :simplified_type, :my_enum_type
end