web-dev-qa-db-fra.com

Possibilité de mapper les valeurs d'énumération au type de chaîne au lieu de l'entier

Les attributs Enum sont excellents et je veux les utiliser. Mais le mappage des valeurs d'énumération en nombre entier rendrait difficile la maintenance du code et de la base de données. De plus, ma base de données serait fortement couplée à mon code que je pense que je devrais considérer comme une mauvaise chose.

Je sais que je peux utiliser un hachage pour organiser un attribut enum avec des paires clé/valeur, mais il serait quand même beaucoup mieux de pouvoir utiliser un tableau et une carte pour chaîne de valeurs dans la base de données.

Existe-t-il un moyen de mapper l'énumération aux chaînes par défaut?

20
Eren CAY

Pour autant que je sache, ce n'est pas possible avec la fonctionnalité d'énumération intégrée d'Active Record. Cependant, il existe quelques joyaux tiers populaires qui font cela. La correspondance la plus proche de ce qui est fourni avec Active Record est probablement énumérer et SimpleEnum .

Cependant, si vous cherchez quelque chose d'un peu différent, je recommanderais ClassyEnum (divulgation complète: je l'ai écrit). Voici certaines de mes notes sur la différence entre énumérer et SimpleEnum vs ClassyEnum:

Les énumérations sans classe (énumération, SimpleEnum) sont idéales pour les cas d'utilisation simples où vous avez juste besoin d'un champ pour représenter l'une d'un ensemble fixe de valeurs. Le principal problème que j'ai avec cette solution est qu'elle encourage les conditions dispersées dans vos modèles, contrôleurs et vues. Il est tentant d'utiliser ces joyaux car ils sont les plus simples à mettre en œuvre, mais le gain à long terme n'est tout simplement pas là, à l'OMI, sauf pour les cas les plus simples.

ClassyEnum a été conçu pour résoudre le problème d'avoir une logique conditionnelle dispersée liée aux différentes énumérations. Vous pouvez toujours l'utiliser pour des collections simples qui n'ont pas de logique, mais lorsque vous avez besoin d'ajouter de la logique (et vous le ferez presque certainement), vous pouvez le pousser dans les classes d'énumération individuelles et profiter du polymorphisme.

8
Peter Brown

En regardant le code pour enum, vous pouvez le faire (au moins dans 4.1+): https://github.com/Rails/rails/blob/master/activerecord/lib/active_record/enum.rb#L96 -98 en passant un hachage, par exemple:

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

Même avec des résultats inattendus lors de l'accès, voir https://github.com/Rails/rails/issues/16459

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

Mise à jour

Ce problème a été résolu dans Rails 5, voir https://github.com/Rails/rails/commit/c51f9b61ce1e167f5f58f07441adcfa117694301 . Merci Yuri.

23
Mihai Târnovan

Que diriez-vous:

class Foo < ApplicationRecord
  NAMES = [
    :foo,
    :bar
  ]

  enum names: NAMES.Zip(NAMES).to_h
end
5
Jay Quigley

Il semble qu'avec Rails 5 API uniquement, un attribut enum d'un modèle sera enregistré dans la base de données sous forme d'entier, mais sera publié dans l'API publique sous forme de chaîne (avec ActiveModel :: Serializer).

Par exemple,

Modèle d'article:

class Article < ApplicationRecord
  enum status: [ :visible, :hidden ]
end

Sérialiseur d'articles:

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

Publiera le json suivant:

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

La réponse courte est non. Vous devrez utiliser une gemme (telle que magic-enum ) si vous voulez faire autre chose que stocker des entiers.

Dans les propres mots de DHH à ce sujet dans les commentaires sur la demande de tirage qui a ajouté cette fonctionnalité :

Il est assez inefficace de stocker des énumérations sous forme de texte. Vous allez répéter le même texte encore et encore et encore. Je considérerais cela comme un motif anti. Les gens feraient mieux de faire une migration vers ints s'ils veulent utiliser cela.

4
pdobb