Rails 4.1の選択から列挙型を保存する


108

Rails 4.1の列挙型を使用して、ワインの色を追跡しています。

Wine.rb

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

私の見解では、ユーザーが特定の色のワインを選択できるように、selectを生成します

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に色を文字列ではなく整数として解釈させる方法はありますか?

回答:


203

さて、明らかに、保存する列挙型の整数値を送信するべきではありません。列挙型のテキスト値を送信する必要があります。

入力を次のように変更しました。

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


8
FWIW、私は配列を表現したf.select :color, Wine.colors.to_a.map { |w| [w[0].humanize, w[0]] }のでそれを作る必要がありましたw。理由は不明ですが、これは誰かを助けるでしょう。
jakealbaugh、2015年

titleize2つ以上の単語がある場合は、使用することをお勧めします
Anwar

8
keysようにこの方法は、配列を返しto_a冗長です。または、selectヘルパーメソッドはオプションとして2D配列を使用するため、を使用できますto_a
xander-miller 2015

「ERROR_JUNK_Submission」などの無効な文字列が送信された場合はどうなりますか。明らかに、このような列挙値はなく、例外がスローされます。どこで捕まえるの?
FlyingV 2015年

モデルWineにはカラーと呼ばれる列挙型があるenum color: [:red, :white, :sparkling]ため、正しい文はf.input :color, :as => :select, :collection => Wine.color.keys.to_a
hguzman

32

enumハッシュをで配列に変換する必要はありませんto_a。これで十分です:

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

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

あなたのロケールで:

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

あなたの見解では:

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

1
編集ではなくmultiplewordclassnameではなく、より一般的なmultiple_word_class_name下MultipleWordClassNameに属する列挙型を見つけることによって、翻訳キーは読みやすくなり
鉄人なし鬼

グレースフルフォールバックのデフォルトを追加するのはどうですか。[I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}", default: key.humanize), key] また、最後のhumanize単語を削除すると、複数の単語があると大文字と小文字が区別されない可能性があります
Peter P.

9

受け入れられたソリューションは、人間が読める形式では機能しませんでしたが、次のように機能させることができました。

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

これは最もきれいでしたが、私は本当に私のキーを人間化する必要がありました:

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

1
rails 5は現在最もクリーンな方法をサポートしています
V-SHY 2017年

@ V-SHY、この方法は何ですか、説明できますか?
ismailarilik

2
@ismailarilik、直接キーを選択オプションとして提供します<%= f.select(:color、Wine.colors.keys)%>
V-SHY

6

Rails 4でenumを使用する場合は、次のように呼び出します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

4

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"

3

enumキーに基づいてi18nを処理する必要がある場合は、以下を使用できます。

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

そして翻訳であなたは色を設定することができます:

wine:
 red: Red
 white: White

1

これが私の解決策です(私の役割には「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 %>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.