# 6. 枚举类型 #### 1. 传统方式 有很多数据或资源是这样,具有一个类型或状态属性,比如,订单有pending,approve状态,博文有草稿(draft),出版(published)的状态,而一般来存这种数据可以选择存成字符串(string),或整型(integer)。建议如果是中文的字符串就不要存进数据库了,不存可以避免很多问题。而大多数人是存整形,就是数字1、2、3之类,比如,1代表draft,2代表published,这样可以节约空间啊,整型肯定比字符串占用的空间小些,如果要读出1或2代表的数据,用一个常量hash来匹配就好了,比如`STATUS_TEXT = { 1: '待处理', 2: '操盘中', 3: '已完结' }`。 而Rails的activerecord也支持enum方法,来支持更多的判断等操作。比如 ``` class Conversation < ActiveRecord::Base enum status: [ :active, :archived ] end # conversation.update! status: 0 conversation.active! conversation.active? # => true conversation.status # => "active" # 返回所有类型 Conversation.statuses # => { "active" => 0, "archived" => 1 } ``` #### 2. PostgreSQL的枚举类型 PostgreSQL官方文档[enum](http://www.postgresql.org/docs/9.1/static/datatype-enum.html)介绍了枚举类型和它的操作。 创建枚举类型。 ``` CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy'); ``` 使用只要指定TYPE的名称即可。 ``` CREATE TABLE person ( name text, current_mood mood ); INSERT INTO person VALUES ('Moe', 'happy'); SELECT * FROM person WHERE current_mood = 'happy'; name | current_mood ------+-------------- Moe | happy (1 row) ``` [functions-enum](http://www.postgresql.org/docs/9.4/static/functions-enum.html)这里有enum所有支持的函数。 #### 2. 在Rails中的使用 添加枚举的列。 ``` # 20151009022320_add_status_to_articles.rb class AddStatusToArticles < ActiveRecord::Migration def up execute <<-SQL CREATE TYPE article_status AS ENUM ('draft', 'published'); SQL add_column :articles, :status, index: true end def down execute <<-SQL DROP TYPE article_status; SQL remove_column :articles, :status end end ``` 在article.rb中定义enum。 ``` # article.rb class Article < ActiveRecord::Base enum status: { draft: 'draft', published: 'published' } end ``` 假如之后有另外的值要添加的话,那也简单。用`ALTER TYPE`命令即可。 ``` ALTER TYPE enum_type ADD VALUE 'new_value'; -- appends to list ALTER TYPE enum_type ADD VALUE 'new_value' BEFORE 'old_value'; ALTER TYPE enum_type ADD VALUE 'new_value' AFTER 'old_value'; ``` 用Rails可以这样做。 ``` disable_ddl_transaction! def up execute <<-SQL ALTER TYPE article_status ADD VALUE IF NOT EXISTS 'archived' AFTER 'published'; SQL end ``` 查看数据库的所有枚举类型可以这样。 ``` SELECT n.nspname AS enum_schema, t.typname AS enum_name, e.enumlabel AS enum_value FROM pg_type t JOIN pg_enum e ON t.oid = e.enumtypid JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace ``` 完结。