跳至内容 跳至搜索

声明一个枚举属性,其中值映射到数据库中的整数,但可以通过名称查询。示例

class Conversation < ActiveRecord::Base
  enum :status, [ :active, :archived ]
end

# conversation.update! status: 0
conversation.active!
conversation.active? # => true
conversation.status  # => "active"

# conversation.update! status: 1
conversation.archived!
conversation.archived? # => true
conversation.status    # => "archived"

# conversation.status = 1
conversation.status = "archived"

conversation.status = nil
conversation.status.nil? # => true
conversation.status      # => nil

基于枚举字段允许值的范围也将提供。使用上面的示例

Conversation.active
Conversation.not_active
Conversation.archived
Conversation.not_archived

当然,如果您不需要范围,也可以直接查询它们

Conversation.where(status: [:active, :archived])
Conversation.where.not(status: :active)

可以通过将:scopes设置为false来禁用定义范围。

class Conversation < ActiveRecord::Base
  enum :status, [ :active, :archived ], scopes: false
end

您可以通过设置:default来设置默认的枚举值,例如

class Conversation < ActiveRecord::Base
  enum :status, [ :active, :archived ], default: :active
end

conversation = Conversation.new
conversation.status # => "active"

可以使用哈希显式映射属性和数据库整数之间的关系

class Conversation < ActiveRecord::Base
  enum :status, active: 0, archived: 1
end

最后,也可以使用字符串列来持久化枚举值。请注意,这可能会导致数据库查询变慢

class Conversation < ActiveRecord::Base
  enum :status, active: "active", archived: "archived"
end

请注意,当使用数组时,从值到数据库整数的隐式映射是从值在数组中出现的顺序派生的。在示例中,:active映射到0,因为它是第一个元素,:archived映射到1。通常,第i个元素映射到数据库中的i-1

因此,一旦将值添加到枚举数组中,就必须保持它在数组中的位置,并且新值只能添加到数组的末尾。要删除未使用的值,应使用显式的哈希语法。

在极少数情况下,您可能需要直接访问映射。映射通过一个具有复数属性名称的类方法公开,该方法返回一个ActiveSupport::HashWithIndifferentAccess

Conversation.statuses[:active]    # => 0
Conversation.statuses["archived"] # => 1

当您需要知道枚举的序数值时,请使用该类方法。例如,当手动构建 SQL 字符串时,您可以使用它

Conversation.where("status <> ?", Conversation.statuses[:archived])

当您需要定义具有相同值的多个枚举时,可以使用:prefix:suffix选项。如果传递的值为true,则方法会以枚举的名称为前缀/后缀。也可以提供自定义值

class Conversation < ActiveRecord::Base
  enum :status, [ :active, :archived ], suffix: true
  enum :comments_status, [ :active, :inactive ], prefix: :comments
end

使用上面的示例,bang 和谓词方法以及相关的范围现在已相应地加上了前缀和/或后缀

conversation.active_status!
conversation.archived_status? # => false

conversation.comments_inactive!
conversation.comments_active? # => false

如果您想在模型上禁用自动生成的 method,可以通过将:instance_methods选项设置为 false 来实现

class Conversation < ActiveRecord::Base
  enum :status, [ :active, :archived ], instance_methods: false
end

如果您希望在保存之前验证枚举值,请使用选项:validate

class Conversation < ActiveRecord::Base
  enum :status, [ :active, :archived ], validate: true
end

conversation = Conversation.new

conversation.status = :unknown
conversation.valid? # => false

conversation.status = nil
conversation.valid? # => false

conversation.status = :active
conversation.valid? # => true

也可以传递其他验证选项

class Conversation < ActiveRecord::Base
  enum :status, [ :active, :archived ], validate: { allow_nil: true }
end

conversation = Conversation.new

conversation.status = :unknown
conversation.valid? # => false

conversation.status = nil
conversation.valid? # => true

conversation.status = :active
conversation.valid? # => true

否则将引发ArgumentError

class Conversation < ActiveRecord::Base
  enum :status, [ :active, :archived ]
end

conversation = Conversation.new

conversation.status = :unknown # 'unknown' is not a valid status (ArgumentError)
方法
E

实例公共方法

enum(name, values = nil, **options)

# File activerecord/lib/active_record/enum.rb, line 216
def enum(name, values = nil, **options)
  values, options = options, {} unless values
  _enum(name, values, **options)
end