rails how enum application ruby-on-rails ruby-on-rails-4 enumeration

ruby on rails - how - Posibilidad de asignar valores de enumeración a tipo de cadena en lugar de entero



rails enum migration (5)

Los atributos de enumeración son geniales y quiero usarlos. Sin embargo, la asignación de valores de enumeración a un entero haría difícil mantener tanto el código como la base de datos. También mi base de datos estaría muy acoplada con mi código, que creo que debería considerar como algo malo.

Sé que puedo usar un hash para organizar un atributo de enumeración con pares clave / valor, pero aún así sería mucho mejor poder usar una matriz y asignar valores de cadena en la base de datos.

¿Hay alguna forma de asignar enumeración a cadenas de forma predeterminada?


La respuesta corta es no. Necesitarás usar una gema (como magic-enum ) si quieres hacer algo más que almacenar números enteros.

En las propias palabras de DHH sobre esto en los comentarios sobre la solicitud de extracción que agregó esta función :

Es bastante ineficiente almacenar enumeraciones como texto. Vas a repetir el mismo texto una y otra vez. Lo consideraría un anti patrón. La gente está mejor haciendo una migración a ints si quieren usar esto.


Mirando el código de enumeración, puede hacer esto (al menos en 4.1+): https://github.com/rails/rails/blob/master/activerecord/lib/active_record/enum.rb#L96-98 al pasar Un hash, por ejemplo:

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

A pesar de los resultados inesperados al acceder, consulte https://github.com/rails/rails/issues/16459

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

Actualizar

Este problema se solucionó en Rails 5, consulte https://github.com/rails/rails/commit/c51f9b61ce1e167f5f58f07441adcfa117694301 . Gracias yuri


Parece que solo con la API de Rails 5, un atributo de enumeración de un modelo se guardará en la base de datos como entero , pero se publicará en la API pública como una cadena (con ActiveModel :: Serializer).

Por ejemplo,

Modelo de artículo:

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

Serializador de artículos:

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

Se publicará el siguiente json:

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


Por lo que sé, no es posible con la funcionalidad de enumeración integrada de Active Record. Sin embargo, hay algunas gemas populares de terceros que hacen esto. La coincidencia más cercana a lo que viene con Active Record es probablemente enumerize y SimpleEnum .

Sin embargo, si está buscando algo un poco diferente, recomendaría ClassyEnum (revelación completa: lo escribí). Estas son algunas de mis notas sobre la diferencia entre enumerize y SimpleEnum vs ClassyEnum:

Las enumeraciones sin clase (enumerize, SimpleEnum) son excelentes para casos de uso simples en los que solo necesita un campo para representar uno de un conjunto fijo de valores. El principal problema que tengo con esta solución es que fomenta los condicionales dispersos en sus modelos, controladores y vistas. Es tentador usar estas gemas porque son las más sencillas de implementar, pero la recompensa a largo plazo simplemente no está ahí IMO para nada más que los casos más simples.

ClassyEnum fue diseñado para resolver el problema de tener lógica condicional dispersa relacionada con las diferentes enumeraciones. Aún puede usarlo para colecciones simples que no tienen lógica, pero cuando necesita agregar lógica (y seguramente lo hará), puede introducir eso en las clases de enumeración individuales y aprovechar el polimorfismo.


Qué tal si:

class Foo < ApplicationRecord NAMES = [ :foo, :bar ] enum names: NAMES.zip(NAMES).to_h end