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方法,来支持更多的判断等操作。比如

  1. class Conversation < ActiveRecord::Base
  2. enum status: [ :active, :archived ]
  3. end
  4. # conversation.update! status: 0
  5. conversation.active!
  6. conversation.active? # => true
  7. conversation.status # => "active"
  8. # 返回所有类型
  9. Conversation.statuses # => { "active" => 0, "archived" => 1 }

2. PostgreSQL的枚举类型

PostgreSQL官方文档enum介绍了枚举类型和它的操作。

创建枚举类型。

  1. CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');

使用只要指定TYPE的名称即可。

  1. CREATE TABLE person (
  2. name text,
  3. current_mood mood
  4. );
  5. INSERT INTO person VALUES ('Moe', 'happy');
  6. SELECT * FROM person WHERE current_mood = 'happy';
  7. name | current_mood
  8. ------+--------------
  9. Moe | happy
  10. (1 row)

functions-enum这里有enum所有支持的函数。

2. 在Rails中的使用

添加枚举的列。

  1. # 20151009022320_add_status_to_articles.rb
  2. class AddStatusToArticles < ActiveRecord::Migration
  3. def up
  4. execute <<-SQL
  5. CREATE TYPE article_status AS ENUM ('draft', 'published');
  6. SQL
  7. add_column :articles, :status, index: true
  8. end
  9. def down
  10. execute <<-SQL
  11. DROP TYPE article_status;
  12. SQL
  13. remove_column :articles, :status
  14. end
  15. end

在article.rb中定义enum。

  1. # article.rb
  2. class Article < ActiveRecord::Base
  3. enum status: {
  4. draft: 'draft',
  5. published: 'published'
  6. }
  7. end

假如之后有另外的值要添加的话,那也简单。用ALTER TYPE命令即可。

  1. ALTER TYPE enum_type ADD VALUE 'new_value'; -- appends to list
  2. ALTER TYPE enum_type ADD VALUE 'new_value' BEFORE 'old_value';
  3. ALTER TYPE enum_type ADD VALUE 'new_value' AFTER 'old_value';

用Rails可以这样做。

  1. disable_ddl_transaction!
  2. def up
  3. execute <<-SQL
  4. ALTER TYPE article_status ADD VALUE IF NOT EXISTS 'archived' AFTER 'published';
  5. SQL
  6. end

查看数据库的所有枚举类型可以这样。

  1. SELECT n.nspname AS enum_schema,
  2. t.typname AS enum_name,
  3. e.enumlabel AS enum_value
  4. FROM pg_type t
  5. JOIN pg_enum e ON t.oid = e.enumtypid
  6. JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace

完结。