Guardar enumeración de select en Rails 4.1


Estoy usando las enumeraciones en Rails 4.1 para hacer un seguimiento de los colores del vino.

Vino.rb

class Wine < ActiveRecord::Base
    enum color: [:red, :white, :sparkling]
end

En mi opinión, genero un select para que el usuario pueda seleccionar un vino con un determinado color

f.input :color, :as => :select, :collection => Wine.colors

Esto genera el siguiente HTML:

<select id="wine_color" name="wine[color]">
  <option value=""></option>
  <option value="0">red</option>
  <option value="1">white</option>
  <option value="2">sparkling</option>
</select>

Sin embargo, al enviar el formulario, recibo un error de argumento que indica '1' is not a valid color. Me doy cuenta de que esto es porque color debe ser igual a 1 y no "1".

¿Hay una manera de forzar los rieles para interpretar el color como un entero en lugar de una cadena?

Author: Brian Weinreich, 2014-05-15

7 answers

Muy bien, por lo que aparentemente, no debe enviar el valor entero de la enumeración que se guardará. Debe enviar el valor de texto de la enumeración.

Cambié la entrada para que fuera la siguiente:

f.input :color, :as => :select, :collection => Wine.colors.keys.to_a

Que generó el siguiente HTML:

<select id="wine_color" name="wine[color]">
  <option value=""></option>
  <option value="red">red</option>
  <option value="white">white</option>
  <option value="sparkling">sparkling</option>
</select>

Los valores pasaron de "0" a "rojo" y ahora estamos listos.


Si estás usando un campo de texto de rails normal es:

f.select :color, Wine.colors.keys.to_a


Si desea tener atributos legibles por humanos limpios, también puede do:

f.select :color, Wine.colors.keys.map { |w| [w.humanize, w] }

 174
Author: Brian Weinreich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-18 21:32:19

No es necesario convertir el hash de enumeración en matriz con to_a. Esto es suficiente:

f.select :color, Wine.colors.map { |key, value| [key.humanize, key] }
 21
Author: Fellow Stranger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-06 10:37:26

La solución aceptada no funcionó para mí para el legible por humanos , pero pude hacer que funcionara de la siguiente manera:

<%= f.select(:color, Wine.colors.keys.map {|key| [key.humanize, key]}) %>

Esta era la más limpia, pero realmente necesitaba humanizar mis llaves:

<%= f.select(:color, Wine.colors.keys) %>
 8
Author: Tom Rossi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-02 21:11:35

Acabo de armar un EnumHelper que pensé que compartiría para ayudar a las personas que necesitan etiquetas de enumeración más personalizadas y locales para su enum selects.

module EnumHelper

  def options_for_enum(object, enum)
    options = enums_to_translated_options_array(object.class.name, enum.to_s)
    options_for_select(options, object.send(enum))
  end

  def enums_to_translated_options_array(klass, enum)
    klass.classify.safe_constantize.send(enum.pluralize).map {
        |key, value| [I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}").humanize, key]
    }
  end

end

En su configuración regional:

 en:
   activerecord:
     enums:
      wine:
        color:
          red:   "Red Wine"
          white:  "White Wine"

En sus puntos de vista:

 <%= f.select(:color, options_for_enum(@wine, :color)) %>
 8
Author: Andrew Cetinic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-31 15:39:48

Si usa enum en Rails 4, simplemente llame a Model.enums:

f.select :color, Wine.colors.keys

Para crear HTML:

<select name="f[color]" id="f_color">
    <option value="red">red</option>
    <option value="white">white</option>
    <option value="sparkling"> sparkling </option>
</select>

O añadir método en el controlador:

def update_or_create
    change_enum_to_i
    ....
end

def change_enum_to_i
    params[:f]["color"] = params[:f]["color"].to_i
end
 3
Author: ogelacinyc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-03 09:07:00

Si necesita manejar el i18n basado en las claves enum, puede usar:

<%= f.select :color, Wine.colors.keys.map {|key| [t("wine.#{key}"), key]} %>

Y en las traducciones puedes establecer los colores:

wine:
 red: Red
 white: White
 2
Author: Paulo Fidalgo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-01 15:37:39

Aquí está mi solución (mis roles tienen guiones bajos en ellos como "sales_rep"), y por alguna razón así fue como necesitaba obtener una opción en blanco para trabajar (con simpleform?):

En la solicitud de ayuda:

def enum_collection_for_select(attribute, include_blank = true)
  x = attribute.map { |r| [r[0].titleize, r[0]] }
  x.insert(0,['', '']) if include_blank == true
  x
end

Entonces en mi forma:

<%= f.input :role, collection: enum_collection_for_select(User.roles), selected: @user.role %>
 1
Author: Greg Blass,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-24 19:42:48