将枚举值映射到字符串类型而不是整数的可能性

22

枚举属性很实用,我想使用它们。但是将枚举值映射到整数会使代码和数据库的维护变得困难。此外,我的数据库会与代码高度耦合,我认为这是一个不好的事情。

我知道可以使用哈希表来组织一个带有键/值对的枚举属性,但仍然最好能够使用数组并将其映射到数据库中的字符串值。

是否有默认的方法将枚举映射为字符串?

5个回答

28

查看枚举的代码,您可以这样做(至少在4.1+):https://github.com/rails/rails/blob/master/activerecord/lib/active_record/enum.rb#L96-98,通过传递一个哈希表,例如:

class Foo
  enum name: {
    foo: 'myfoo',
    bar: 'mybar'
  }

尽管访问它时会出现意外结果,请参见https://github.com/rails/rails/issues/16459

foo_instance.foo!
foo_instance.name
=> "foo"
foo_instance[:name]
=> "myfoo"

更新

这个问题已在Rails 5修复,详情请参见https://github.com/rails/rails/commit/c51f9b61ce1e167f5f58f07441adcfa117694301。谢谢Yuri。


已经修复:https://github.com/rails/rails/commit/c51f9b61ce1e167f5f58f07441adcfa117694301 - Yuri Ghensev

8
据我所知,使用Active Record内置的枚举功能是不可能的。但是,有一些受欢迎的第三方gems可以实现这一点。与Active Record一起提供的最接近的匹配可能是enumerizeSimpleEnum
不过,如果您想要一些略微不同的东西,我建议使用ClassyEnum(完全透明:我自己编写了它)。这里是关于枚举化和SimpleEnum与ClassyEnum之间差异的一些笔记
无类枚举(enumerize、SimpleEnum)非常适合简单的使用场景,其中您只需要一个字段来表示一组固定的值。我对这种解决方案的主要问题是它鼓励在模型、控制器和视图中散布条件语句。尽管这些 gem 最容易实现,但我认为除了最简单的情况外,长期回报并不足够。 ClassyEnum 的设计目的是解决与不同枚举相关的条件逻辑分散的问题。您仍然可以将其用于没有逻辑的简单集合,但当您需要添加逻辑时(几乎肯定会),您可以将其推入各个枚举类中,并利用多态性。

顺便说一句,对于十年后偶然发现这篇文章的人来说,这个功能现在确实已经被支持在Rails核心中,并且已经有好几年了。 - courtsimas

7
似乎在Rails 5中,仅使用API,模型的枚举属性将被保存在数据库为整数,但将以字符串形式(使用ActiveModel::Serializer)发布到公共API
例如,文章模型:
class Article < ApplicationRecord
  enum status: [ :visible, :hidden ]
end

文章序列化器:

class ArticleSerializer < ActiveModel::Serializer
  attributes :id, :status, :title, :body
end

将发布以下json:
{
  "id": "1",
  "type": "articles",
  "attributes": {
    "status": "visible",
    "title": "Enums are passed as string in a json API render",
    "body": "Great!",
}

这正是我需要的,但序列化程序和JSON输出之间似乎存在差距。文章/ ID和属性值之间的映射放在哪里? - Gijs P

6
如何考虑:
class Foo < ApplicationRecord
  NAMES = [
    :foo,
    :bar
  ]

  enum names: NAMES.zip(NAMES).to_h
end

4
短答案是否定的。如果您想要存储除整数以外的任何内容,您需要使用一个 gem(例如 magic-enum)。
在 DHH 的评论中,他自己说道:将枚举存储为文本是相当低效的。您会一遍又一遍地重复相同的文本。我认为这是反模式。如果人们想要使用此功能,最好进行迁移以使用整数。 (添加此功能的拉取请求 中的评论)

3
DHH也说:“我很乐意看到数据库的枚举支持这一点。” 这比使用整数更接近于使用字符串。 不确定是否有任何进展。 - Peter Brown
9
DHH 的观点有一定道理,但我不认为使用“模棱两可且难以维护”的整数比一遍又一遍地重复相同的“有意义且易于维护”的字符串更好。 - Eren CAY
1
将字符串存储起来并不算离谱,因为布尔值通常被存储为字符。 - SirWolfgang
11
哈!他太虚伪了。那DHH为什么不实现基于整型的多态关联呢?“type: 'CompanyAddress'”占用了大量空间... - Volte
鉴于多态关联的概念...您如何确保字符串的顺序(因此它们的整数值)不会改变?这就是他不这样做的原因。 - twilson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接