跳至内容 跳至搜索

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

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-th 元素映射到 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 方法和 predicate 方法以及相关的范围现在都相应地带有前缀和/或后缀。

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

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

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

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

默认情况下,在分配无效值时将引发 ArgumentError

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

conversation = Conversation.new

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

如果希望在保存之前验证枚举值,请使用 :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
方法
E

实例公共方法

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

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