【发布时间】:2014-07-29 03:20:54
【问题描述】:
枚举属性很棒,我想使用它们。但是将枚举值映射到整数会使代码和数据库都难以维护。此外,我的数据库将与我的代码高度耦合,我认为我应该认为这是一件坏事。
我知道我可以使用散列来组织带有键/值对的枚举属性,但是能够使用数组并映射到数据库中的字符串值仍然会好得多。
默认情况下有没有办法将枚举映射到字符串?
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-4 enumeration
枚举属性很棒,我想使用它们。但是将枚举值映射到整数会使代码和数据库都难以维护。此外,我的数据库将与我的代码高度耦合,我认为我应该认为这是一件坏事。
我知道我可以使用散列来组织带有键/值对的枚举属性,但是能够使用数组并映射到数据库中的字符串值仍然会好得多。
默认情况下有没有办法将枚举映射到字符串?
【问题讨论】:
标签: ruby-on-rails ruby-on-rails-4 enumeration
查看枚举的代码,您可以这样做(至少在 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。谢谢尤里。
【讨论】:
据我所知,使用 Active Record 的内置枚举功能是不可能的。但是,有一些流行的 3rd 方宝石可以做到这一点。与 Active Record 最接近的匹配可能是 enumerize 和 SimpleEnum。
但是,如果您正在寻找一些不同的东西,我推荐ClassyEnum(完全披露:我写的)。以下是 some of my notes 关于 enumerize 和 SimpleEnum 与 ClassyEnum 的区别:
无类枚举(enumerize、SimpleEnum)非常适合简单使用 您只需要一个字段来表示一组固定的一组 价值观。我对这个解决方案的主要问题是它鼓励 分散在你的模型、控制器和视图中的条件。 使用这些宝石很诱人,因为它们是最简单的 实施,但长期的回报就是没有任何东西IMO 但最简单的情况。
ClassyEnum 旨在解决分散的问题 与不同枚举相关的条件逻辑。你仍然可以使用它 对于没有逻辑的简单集合,但当你确实需要时 添加逻辑(你几乎肯定会),你可以把它推到 单独的枚举类并利用多态性。
【讨论】:
似乎仅使用 Rails 5 API,模型的枚举属性将保存在数据库中作为整数,但将在公共 API 中发布作为字符串 (使用 ActiveModel::Serializer)。
例如,
文章型号:
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!",
}
【讨论】:
怎么样:
class Foo < ApplicationRecord
NAMES = [
:foo,
:bar
]
enum names: NAMES.zip(NAMES).to_h
end
【讨论】:
简短的回答是否定的。如果您想要做任何事情而不是存储整数,则需要使用 gem(例如 magic-enum)。
the pull request that added this feature 上的 cmets 用 DHH 自己的话说:
将枚举存储为文本是非常低效的。您将一遍又一遍地重复相同的文本。我认为这是一种反模式。如果人们想使用它,最好迁移到整数。
【讨论】:
type: 'CompanyAddress' 占用了大量空间......