Speichern der Aufzählung von select in Rails 4.1

108

Ich verwende die Aufzählungen in Rails 4.1, um die Farben des Weins zu verfolgen.

Wine.rb

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

Aus meiner Sicht generiere ich eine Auswahl, damit der Benutzer einen Wein mit einer bestimmten Farbe auswählen kann

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

Dies generiert den folgenden HTML-Code:

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

Beim Absenden des Formulars erhalte ich jedoch einen Argumentationsfehler '1' is not a valid color. Mir ist klar, dass dies daran liegt, dass colores gleich sein muss 1und nicht "1".

Gibt es eine Möglichkeit, Rails zu zwingen, die Farbe als Ganzzahl und nicht als Zeichenfolge zu interpretieren?

Brian Weinreich
quelle

Antworten:

203

Okay, anscheinend sollten Sie den ganzzahligen Wert der zu speichernden Aufzählung nicht senden. Sie sollten den Textwert der Aufzählung senden.

Ich habe die Eingabe wie folgt geändert:

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

Welches erzeugte den folgenden 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>

Die Werte gingen von "0" auf "rot" und jetzt sind wir alle eingestellt.


Wenn Sie ein normales altes Schienen-Textfeld verwenden, ist es:

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


Wenn Sie saubere, für Menschen lesbare Attribute haben möchten, können Sie auch Folgendes tun:

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

Brian Weinreich
quelle
8
FWIW, ich musste es machen, f.select :color, Wine.colors.to_a.map { |w| [w[0].humanize, w[0]] }weil es wein Array darstellte. Ich weiß nicht warum, aber vielleicht hilft das jemandem.
Jakealbaugh
Verwenden titleizekönnte eine bessere Idee sein, wenn Sie zwei oder mehr Wörter haben
Anwar
8
Die keysMethode gibt ein Array zurück, sodass das to_aredundant ist. Alternativ verwendet die Select-Helper-Methode ein 2D-Array für Optionen, die Sie einfach verwenden können to_a.
Xander-Miller
Was passiert, wenn eine ungültige Zeichenfolge wie "ERROR_JUNK_Submission" gesendet wird? Offensichtlich gibt es keinen solchen Aufzählungswert, und eine Ausnahme wird ausgelöst. Wo würden wir es fangen?
FlyingV
Das Modell Wine hat eine Aufzählung namens Farbe, enum color: [:red, :white, :sparkling]daher lautet der richtige Satzf.input :color, :as => :select, :collection => Wine.color.keys.to_a
hguzman
32

Es ist nicht erforderlich, den Enum-Hash in ein Array mit zu konvertieren to_a. Das reicht aus:

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

Ich habe gerade einen EnumHelper zusammengestellt, den ich teilen möchte, um Menschen zu helfen, die individuellere Enum-Labels und Gebietsschemas für Ihre Enum-Auswahl benötigen.

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 Ihrem Gebietsschema:

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

In Ihren Ansichten:

 <%= f.select(:color, options_for_enum(@wine, :color)) %>
Andrew Cetinic
quelle
1
Die Bearbeitung macht die Übersetzungsschlüssel besser lesbar, indem Aufzählungen, die zu MultipleWordClassName gehören, unter dem eher typischen Namen mehrerer Klassenwörter statt unter dem Namen mehrerer Wörter gefunden werden
Tetsujin no Oni
Wie wäre es mit dem Hinzufügen eines Standardwerts für einen anmutigen Fallback: [I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}", default: key.humanize), key] Entfernen Sie auch den letzten, humanizeda dies die Großschreibung verzerren kann, wenn mehrere Wörter vorhanden sind
Peter P.
9

Die akzeptierte Lösung funktionierte für mich für den Menschen nicht lesbar , aber ich konnte sie so zum Laufen bringen:

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

Dies war das sauberste, aber ich musste meine Schlüssel wirklich humanisieren:

<%= f.select(:color, Wine.colors.keys) %>
Tom Rossi
quelle
1
Schienen 5 unterstützt jetzt den saubersten Weg
V-SHY
@ V-SHY, was ist das, kannst du das erklären?
ismailarilik
2
@ismailarilik, geben Sie die Schlüssel direkt als Auswahloption an, <% = f.select (: color, Wine.colors.keys)%>
V-SHY
6

Wenn Sie in Rails 4 enum verwenden, rufen Sie einfach an Model.enums:

f.select :color, Wine.colors.keys

So erstellen Sie HTML:

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

Oder fügen Sie eine Methode im Controller hinzu:

def update_or_create
    change_enum_to_i
    ....
end

def change_enum_to_i
    params[:f]["color"] = params[:f]["color"].to_i
end
ogelacinyc
quelle
4

Folgendes hat bei mir funktioniert, 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 habe my _form.html.erbich das:

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

Test von der Konsole nach dem Hinzufügen eines Datensatzes:

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

Wenn Sie den i18n basierend auf den Aufzählungstasten handhaben müssen, können Sie Folgendes verwenden:

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

und in den Übersetzungen können Sie die Farben einstellen:

wine:
 red: Red
 white: White
Paulo Fidalgo
quelle
1

Hier ist meine Lösung (meine Rollen haben Unterstriche wie "sales_rep"), und aus irgendeinem Grund musste ich eine leere Option zum Arbeiten bekommen (mit einfacher Form?):

In 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

Dann in meiner Form:

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