Возможность сопоставления значений перечисления с строковым типом вместо целого
Атрибуты Enum великолепны, и я хочу их использовать. Но преобразование значений перечисления в integer затрудняло бы поддержание как кода, так и базы данных. Кроме того, моя база данных будет тесно связана с моим кодом, который, я думаю, должен считать, что это плохо.
Я знаю, что могу использовать хеш для организации атрибута enum с парами ключ/значение, но все же было бы намного лучше использовать массив и сопоставить строковые значения в базе данных.
Есть ли способ по умолчанию перечислить строки в строки?
Ответы
Ответ 1
Насколько я знаю, это невозможно при использовании встроенных функций enum Active Record. Тем не менее, есть несколько популярных сторонних драгоценных камней, которые делают это. Самое близкое совпадение с тем, что происходит с Active Record, вероятно, enumerize и SimpleEnum.
Однако, если вы ищете что-то немного другое, я бы рекомендовал ClassyEnum (полное раскрытие: я его написал). Вот некоторые из моих заметок о различии между перечислением и SimpleEnum vs ClassyEnum:
Перечисления класса (enumerize, SimpleEnum) отлично подходят для простого использования случаи, когда вам просто нужно поле для представления одного из фиксированного набора значения. Основной вопрос, который у меня есть с этим решением, заключается в том, что он поощряет условные обозначения, разбросанные по всем вашим моделям, контроллерам и представлениям. Заманчиво использовать эти драгоценные камни, потому что они самые простые но долгосрочный выигрыш просто не существует ИМО для чего-либо но простейшие случаи.
ClassyEnum был разработан для решения проблемы рассеяния условная логика, связанная с различными перечислениями. Вы все еще можете использовать его для простых коллекций, у которых нет логики, но когда вам нужно добавьте логику (и вы почти наверняка будете), вы можете отдельные классы enum и использовать полиморфизм.
Ответ 2
Посмотрев код для перечисления, вы можете сделать это (по крайней мере, в 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'
}
Alltough с неожиданными результатами при доступе к нему см. https://github.com/rails/rails/issues/16459
foo_instance.foo!
foo_instance.name
=> "foo"
foo_instance[:name]
=> "myfoo"
Ответ 3
Короткий ответ - нет. Вам нужно будет использовать драгоценный камень (например, magic-enum), если вы хотите делать что-либо, кроме целых чисел.
В своих собственных словах DHH из комментариев на запрос на перенос, который добавил эту функцию:
Это довольно неэффективно для хранения перечислений в виде текста. Вы повторяете один и тот же текст снова и снова. Я считаю, что это анти-шаблон. Людям лучше делать переход к ints, если они хотят использовать это.
Ответ 4
Похоже, что только с Rails 5 API атрибут enum будет сохраняться в базе данных как целое, но будет опубликован в общедоступном API в виде строки (с помощью ActiveModel:: Сериализатор).
Например,
Модель статьи:
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!",
}
Ответ 5
Как насчет:
class Foo < ApplicationRecord
NAMES = [
:foo,
:bar
]
enum names: NAMES.zip(NAMES).to_h
end