从Rails 4.1中的select中保存枚举

Bri*_*ich 101 ruby enums ruby-on-rails ruby-on-rails-4

我正在使用Rails 4.1中的枚举来跟踪葡萄酒的颜色.

Wine.rb

class Wine < ActiveRecord::Base
    enum color: [:red, :white, :sparkling]
end
Run Code Online (Sandbox Code Playgroud)

在我看来,我生成一个选择,以便用户可以选择具有特定颜色的葡萄酒

f.input :color, :as => :select, :collection => Wine.colors
Run Code Online (Sandbox Code Playgroud)

这会生成以下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>
Run Code Online (Sandbox Code Playgroud)

但是,在提交表单时,我收到一个参数错误说明'1' is not a valid color.我意识到这是因为color必须平等1而不是"1".

有没有办法强制Rails将颜色解释为整数而不是字符串?

Bri*_*ich 198

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

我将输入更改为以下内容:

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>
Run Code Online (Sandbox Code Playgroud)

值从"0"变为"红色",现在我们都已设置好.


如果您正在使用常规的ol'trail text_field,那就是:

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


如果您想拥有干净的人类可读属性,您还可以:

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

  • FWIW,我需要把它变成`f.select:color,Wine.colors.to_a.map {| w | [w [0] .humanize,w [0]]}`因为`w`代表一个数组.不知道为什么,但也许这会对某人有所帮助. (8认同)
  • `keys`方法返回一个数组,因此`to_a`是多余的.或者,select辅助方法采用2D数组作为选项,因此您只需使用`to_a`. (8认同)
  • 行`f.select:color,Wine.colors.keys.to_a`就像一个魅力.非常感谢. (4认同)

Fel*_*ger 31

无需将枚举哈希转换为数组to_a.这足够了:

f.select :color, Wine.colors.map { |key, value| [key.humanize, key] }
Run Code Online (Sandbox Code Playgroud)


And*_*nic 10

我刚刚整理了一个EnumHelper,我认为我将分享这些内容,以帮助那些需要更多自定义枚举标签和区域设置的人.

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
Run Code Online (Sandbox Code Playgroud)

在您的语言环境中:

 en:
   activerecord:
     enums:
      wine:
        color:
          red:   "Red Wine"
          white:  "White Wine"
Run Code Online (Sandbox Code Playgroud)

在您的观点中:

 <%= f.select(:color, options_for_enum(@wine, :color)) %>
Run Code Online (Sandbox Code Playgroud)


Tom*_*ssi 9

已接受的解决方案对我来说对人类可读不起作用,但我能够让它像这样工作:

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

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

<%= f.select(:color, Wine.colors.keys) %>
Run Code Online (Sandbox Code Playgroud)

  • @ismailarilik,直接提供键作为选择选项,<%= f.select(:color,Wine.colors.keys)%> (2认同)

小智 6

如果你在Rails 4中使用枚举,那么只需调用Model.enums:

f.select :color, Wine.colors.keys
Run Code Online (Sandbox Code Playgroud)

要创建HTML:

<select name="f[color]" id="f_color">
    <option value="red">red</option>
    <option value="white">white</option>
    <option value="sparkling"> sparkling </option>
</select>
Run Code Online (Sandbox Code Playgroud)

或者在控制器中添加方法:

def update_or_create
    change_enum_to_i
    ....
end

def change_enum_to_i
    params[:f]["color"] = params[:f]["color"].to_i
end
Run Code Online (Sandbox Code Playgroud)


Pau*_*lgo 5

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

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

在翻译中您可以设置颜色:

wine:
 red: Red
 white: White
Run Code Online (Sandbox Code Playgroud)


zee*_*zee 5

以下是对我有用的 Rails 4+:

class Contract < ApplicationRecord

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


end
Run Code Online (Sandbox Code Playgroud)

在 中my _form.html.erb,我有这个:

  <div class="field">
    <%= form.select :status, Contract.statuses.keys, {}%>
  </div>
Run Code Online (Sandbox Code Playgroud)

添加记录后从控制台进行测试:

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