【问题标题】:Saving enum from select in Rails 4.1在 Rails 4.1 中从选择中保存枚举
【发布时间】:2014-07-04 08:59:19
【问题描述】:

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

Wine.rb

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

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

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

这会生成以下 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>

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

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

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4 enums


    【解决方案1】:

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

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

    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
    

    如果你想拥有清晰的人类可读属性,你也可以这样做:

    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 表示一个数组。不知道为什么,但也许这会对某人有所帮助。
    • 如果您有两个或更多单词,使用titleize 可能会更好
    • keys 方法返回一个数组,因此to_a 是多余的。或者,选择辅助方法采用二维数组作为选项,因此您可以使用 to_a
    • 如果发送了“ERROR_JUNK_Submission”等无效字符串怎么办。显然没有这样的枚举值,抛出异常。我们会在哪里抓到它?
    • 模型 Wine 有一个名为 color enum color: [:red, :white, :sparkling]的枚举,所以正确的句子是 f.input :color, :as =&gt; :select, :collection =&gt; Wine.color.keys.to_a
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      我刚刚整理了一个 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
      

      在您的地区:

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

      在你看来:

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

      【讨论】:

      • 通过在更典型的 multiple_word_class_name 而不是 multiplewordclassname 下查找属于 MultipleWordClassName 的枚举,编辑使翻译键更具可读性
      • 如何添加一个默认的优雅回退:[I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}", default: key.humanize), key] 另外,删除最后一个humanize,因为如果它有多个单词可能会扭曲大写
      【解决方案4】:

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

      f.select :color, Wine.colors.keys
      

      创建 HTML:

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

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

      def update_or_create
          change_enum_to_i
          ....
      end
      
      def change_enum_to_i
          params[:f]["color"] = params[:f]["color"].to_i
      end
      

      【讨论】:

        【解决方案5】:

        这是我的解决方案(我的角色中有下划线,例如“sales_rep”),出于某种原因,这就是我需要获得空白选项的方式(使用 simpleform?):

        在 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
        

        然后以我的形式:

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

        【讨论】:

          【解决方案6】:

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

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

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

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

          【讨论】:

          • rails 5 现在支持最干净的方式
          • @V-SHY,这是什么路,能解释一下吗?
          • @ismailarilik,直接提供键作为选择选项,
          【解决方案7】:

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

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

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

          wine:
           red: Red
           white: White
          

          【讨论】:

            【解决方案8】:

            这对我有用,Rails 4+:

            class Contract < ApplicationRecord
            
            enum status: { active:  "active", 
                           ended: "active", 
                           on_hold: "on_hold", 
                           terminated:  "terminated", 
                           under_review:  "under_review" , 
                           unknown: "unknown" 
                          }
            
            
            end
            

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

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

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

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

            【讨论】:

              【解决方案9】:

              对我来说,以下方法也很有效:

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

              【讨论】:

                猜你喜欢
                • 2014-02-08
                • 1970-01-01
                • 1970-01-01
                • 2017-03-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-06-18
                • 1970-01-01
                相关资源
                最近更新 更多