20

PostgreSQL具有内置于数据库中的enumerated types的概念。如何在Rails 3的Postgres数据库中使用枚举?

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

在Rails 3.07,Ruby 1.92p180,PostgreSQL 8.3中工作。

+0

什么EXAC tly可以防止你通过迁移在Postgresql中添加这个枚举,并在之后使用它? – plang

回答

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 enums。该validates_inclusion_of现在可以改为:

enum gender: [ :male, :female ] 

(然而,这仍然不是原生底层的数据库支持,所以仍需要本地SQL迁移。)

+3

这意味着你永远无法做一个模式:尽管加载,因为它打破了shema.rb。对于mysql,有rubygem-enum_column3宝石。不知道修改postgres以及修改它有多困难。 – yxhuvud

+0

感谢您的信息。我很少使用'ENUM'或'schema:load';) – rdvdijk

+0

您没有任何测试?该使用模式:加载。您的测试数据库枚举最终将以字符串结尾。 – yxhuvud

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文件。

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 
+1

非常有趣。此外,让ActiveRecord自动将':: my_enum'转换为特定常量的方式将会非常棒。 – rewritten

+0

@rewritten有可能让rails自动转换它,请参阅https://github.com/rails/rails/pull/7324中的点类型以供参考。如果你想提交一个PR到rails,我很乐意提供帮助(还需要schema.rb支持才能成为主)。 – glebm

+0

我认为这是针对特定的类型,你是否建议有一些代码来管理任意的用户定义类型或只是枚举?让我们继续通过推特,只是跟着你... – rewritten

相关问题