Сохранение перечисления из списка в Rails 4.1
Я использую перечисления в 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 интерпретировать цвет как целое, а не строку?
Ответы
Ответ 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] }
Ответ 2
Не нужно преобразовывать хэш хэша в массив с помощью to_a
. Этого достаточно:
f.select :color, Wine.colors.map { |key, value| [key.humanize, key] }
Ответ 3
Я просто собрал EnumHelper, которым, как я думал, я бы поделился, чтобы помочь людям, которым нужны более настраиваемые метки enum и локали для выбора enum.
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)) %>
Ответ 4
Принятое решение не помогло мне для человека, читаемого, но я смог заставить его работать следующим образом:
<%= f.select(:color, Wine.colors.keys.map {|key| [key.humanize, key]}) %>
Это было самое чистое, но мне действительно нужно было очеловечить мои ключи:
<%= f.select(:color, Wine.colors.keys) %>
Ответ 5
Если вы используете перечисление в 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
Ответ 6
Вот что сработало для меня, 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"
Ответ 7
Если вам нужно обработать i18n на основе ключей перечисления, вы можете использовать:
<%= f.select :color, Wine.colors.keys.map {|key| [t("wine.#{key}"), key]} %>
а в каналах вы можете установить цвета:
wine:
red: Red
white: White
Ответ 8
Здесь мое решение (у моих ролей есть подчеркивания в них, такие как "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 %>