Saving enum from select in Rails 4.1

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 because color must equal 1 and not "1".

Is there a way to force Rails to interpret the color as an integer rather than a string?

63521 次浏览

好的,显然,您不应该发送要保存的枚举的整数值。您应该发送枚举的文本值。

我将输入更改为如下:

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

产生以下 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>

数值从“0”变成了“红色”现在我们都设置好了。


如果你使用一个常规的 ol’rails text _ field,它是:

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] }

不需要使用 to_a将枚举散列转换为数组。这就足够了:

f.select :color, Wine.colors.map { |key, value| [key.humanize, key] }

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"

在你看来:

 <%= f.select(:color, options_for_enum(@wine, :color)) %>

如果您在 Rails 4中使用 enum,那么只需调用 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

下面是我的解决方案(我的角色中有下划线,比如“ sales _ rep”) ,出于某种原因,这就是我需要获得一个空白选项来工作的方法(使用 simpleform?):

在申请中帮助:

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

然后以我的形式:

<%= f.input :role, collection: enum_collection_for_select(User.roles), selected: @user.role %>

The accepted solution didn't work for me for the 人类可读性, but I was able to get it to work like this:

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

这是最干净的,但我真的需要人性化我的钥匙:

<%= f.select(:color, Wine.colors.keys) %>

如果需要根据枚举键处理 i18n,可以使用:

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

and in the tranlations you can set the colors:

wine:
red: Red
white: White

以下是我的成功之道,Rails 4 + :

class Contract < ApplicationRecord


enum status: { active:  "active",
ended: "active",
on_hold: "on_hold",
terminated:  "terminated",
under_review:  "under_review" ,
unknown: "unknown"
}




end

in my _form.html.erb , I have this:

  <div class="field">
<%= form.select :status, Contract.statuses.keys, {}%>
</div>

添加记录后从 Console 测试:

2.3.0 :001 > Contract.last.status
Contract Load (0.2ms)  SELECT  "contracts".* FROM "contracts" ORDER BY "contracts"."id" DESC LIMIT ?  [["LIMIT", 1]]
=> "active"

对我来说,以下方法同样奏效:

= f.input :color, collection: Wine.colors.keys.map{ |key| [key.humanize, key] }, include_blank: false