Збереження перерахунку від вибору в Rails 4.1


108

Я використовую переліки в Rails 4.1, щоб відстежувати кольори вина.

Вино.рб

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 інтерпретувати колір як ціле число, а не рядок?

Відповіді:


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

використання titleizeможе бути кращою ідеєю, якщо у вас є два або більше слів
Anwar

8
keysметод повертає масив таким чином , to_aє надмірною. Крім того, метод вибору помічника має 2D масив для параметрів, щоб ви могли просто використовувати to_a.
xander-miller

Що робити, якщо буде надісланий недійсний рядок типу "ERROR_JUNK_Submission". Очевидно, що немає такої величини enum, як ця, і є виняток. Де ми б його спіймали?
ЛетитьV

Модель 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
Tetsujin no Oni

Як щодо додавання за замовчуванням витонченого запасного: [I18n.t("activerecord.enums.#{klass.underscore}.#{enum}.#{key}", default: key.humanize), key] Також видаліть останнє, humanizeоскільки воно може спотворити великі літери, якщо його кілька слів
Пітер П.

9

Прийняте рішення не працювало для мене для людського читання , але я зміг змусити його працювати так:

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

Це було найчистішим, але мені справді потрібно було гуманізувати свої ключі:

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

1
рейки 5 підтримують найчистіший спосіб
V-SHY

@ V-SHY, що це за спосіб, ви можете пояснити?
ismailarilik

2
@ismailarilik, надайте безпосередньо клавіші як опцію вибору, <% = f.select (: color, Wine.colors.keys)%>
V-SHY

6

Якщо ви використовуєте enum в 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

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

Якщо вам потрібно обробити i18n на основі клавіш enum, ви можете використовувати:

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

і в перекладах ви можете встановити кольори:

wine:
 red: Red
 white: White

1

Ось моє рішення (мої ролі мають в них підкреслення як "sales_rep"), і чомусь мені так потрібно було отримати пусту опцію для роботи (з простою формою?):

У програмі 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 %>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.