ruby on rails - how - Guardar enumeración de select en Rails 4.1
rails enum migration (7)
Acabo de armar un EnumHelper que pensé que compartiría para ayudar a las personas que necesitan etiquetas enum más personalizadas y configuraciones regionales para su enum selecciona.
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.downcase}.#{enum}.#{key}").humanize, key]
}
end
end
En tu localidad:
en:
activerecord:
enums:
wine:
color:
red: "Red Wine"
white: "White Wine"
En tus puntos de vista:
<%= f.select(:color, options_for_enum(@wine, :color)) %>
Estoy usando las enumeraciones en Rails 4.1 para realizar un seguimiento de los colores del vino.
Wine.rb
class Wine < ActiveRecord::Base
enum color: [:red, :white, :sparkling]
end
En mi opinión, genero una selección para que el usuario pueda seleccionar un vino con un cierto 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 que ''1'' is not a valid color
. Me doy cuenta de que esto se debe a que el color
debe ser igual a 1
y no a "1"
.
¿Hay alguna manera de forzar a Rails a interpretar el color como un entero en lugar de una cadena?
Aquí está mi solución (mis roles se destacan en ellos como "sales_rep"), y por alguna razón, así era como necesitaba obtener una opción en blanco para trabajar (¿con la forma simple?):
En ApplicationHelper:
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 %>
De acuerdo, aparentemente, no deberías enviar el valor entero de la enumeración para guardar. Debe enviar el valor de texto de la enumeración.
Cambié la entrada para que sea 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á utilizando un campo de texto de ol ''rails normal, es:
f.select :color, Wine.colors.keys.to_a
Si desea tener atributos limpios legibles para el ser humano, también puede hacer:
f.select :color, Wine.colors.keys.map { |w| [w.humanize, w] }
La solución aceptada no funcionó para mí para la lectura humana , pero pude hacer que funcionara así:
<%= f.select(:color, Wine.colors.keys.map {|key| [key.humanize, key]}) %>
Este fue el más limpio, pero realmente necesitaba humanizar mis llaves:
<%= f.select(:color, Wine.colors.keys) %>
No es necesario convertir el enum hash al array con to_a
. Esto es suficiente
f.select :color, Wine.colors.map { |key, value| [key.humanize, key] }
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
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 agregue el 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