Saving enum from select in Rails 4.1
Solution 1
Alright, so apparently, you shouldn't send the integer value of the enum to be saved. You should send the text value of the enum.
I changed the input to be the following:
f.input :color, :as => :select, :collection => Wine.colors.keys.to_a
Which generated the following 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>
Values went from "0" to "red" and now we're all set.
If you're using a regular ol' rails text_field it's:
f.select :color, Wine.colors.keys.to_a
If you want to have clean human-readable attributes you can also do:
f.select :color, Wine.colors.keys.map { |w| [w.humanize, w] }
Solution 2
No need converting the enum hash to array with to_a
. This suffice:
f.select :color, Wine.colors.map { |key, value| [key.humanize, key] }
Solution 3
The accepted solution didn't work for me for the human readable, but I was able to get it to work like this:
<%= f.select(:color, Wine.colors.keys.map {|key| [key.humanize, key]}) %>
This was the cleanest, but I really needed to humanize my keys:
<%= f.select(:color, Wine.colors.keys) %>
Solution 4
I just put together an EnumHelper that I thought I'd share to help people who need more customised enum labels and locales for your 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}"), key]
}
end
end
In your locale:
en:
activerecord:
enums:
wine:
color:
red: "Red Wine"
white: "White Wine"
In your views:
<%= f.select(:color, options_for_enum(@wine, :color)) %>
Solution 5
If you use enum in Rails 4 then just call Model.enums
:
f.select :color, Wine.colors.keys
To create HTML:
<select name="f[color]" id="f_color">
<option value="red">red</option>
<option value="white">white</option>
<option value="sparkling"> sparkling </option>
</select>
Or add method in controller:
def update_or_create
change_enum_to_i
....
end
def change_enum_to_i
params[:f]["color"] = params[:f]["color"].to_i
end
Related videos on Youtube
Comments
-
Brian Weinreich almost 3 years
I am using the enums in Rails 4.1 to keep track of colors of wine.
Wine.rb
class Wine < ActiveRecord::Base enum color: [:red, :white, :sparkling] end
In my view, I generate a select so the user can select a wine with a certain color
f.input :color, :as => :select, :collection => Wine.colors
This generates the following 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>
However, upon submitting the form, I receive an argument error stating
'1' is not a valid color
. I realize this is becausecolor
must equal1
and not"1"
.Is there a way to force Rails to interpret the color as an integer rather than a string?
-
TPR about 2 yearsWhere did the "input" method come from? Thanks
-
-
jakealbaugh almost 9 yearsFWIW, I needed to make it
f.select :color, Wine.colors.to_a.map { |w| [w[0].humanize, w[0]] }
becausew
represented an array. Not sure why, but maybe this will help someone. -
Anwar over 8 yearsusing
titleize
might be a better idea if you have two or more words -
xander-miller over 8 yearsthe
keys
method returns an array so theto_a
is redundant. Alternatively the select helper method takes a 2D array for options so you can just useto_a
. -
FlyingV over 8 yearsWhat if an Invalid String is sent such as "ERROR_JUNK_Submission". Obviously there is no enum value such as this, and an exception is thrown. Where would we catch it?
-
V-SHY over 7 yearsrails 5 supports the cleanest way now
-
ismailarilik almost 7 years@V-SHY, what is this way, can you explain?
-
V-SHY almost 7 years@ismailarilik, directly provide the keys as select option, <%= f.select(:color, Wine.colors.keys) %>
-
Tetsujin no Oni over 5 yearsThe edit makes the translation keys more readable by finding enums belonging to MultipleWordClassName under the rather more typical multiple_word_class_name rather than multiplewordclassname
-
Peter P. over 5 yearsHow about adding in a default for a graceful fallback:
[I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}", default: key.humanize), key]
Also, remove the lasthumanize
as it may distort capitalization if its multiple words -
hguzman about 4 yearsThe model Wine has a enum called color
enum color: [:red, :white, :sparkling]
so the correct sentence isf.input :color, :as => :select, :collection => Wine.color.keys.to_a