модуль ActionView::Helpers::FormOptionsHelper
Помощники параметров форм Action View
Предоставляет ряд методов для преобразования различных типов контейнеров в набор тегов параметров.
Методы collection_select, select и time_zone_select принимают параметр options — хеш:
-
:include_blank— задайте значение true или строку-подсказку, если первый элемент параметра select должен быть пустым. Полезно, если для элемента select не требуется значение по умолчанию.select(:post, :category, Post::CATEGORIES, { include_blank: true })может превратиться в:
<select name="post[category]" id="post_category"> <option value="" label=" "></option> <option value="joke">joke</option> <option value="poem">poem</option> </select>
Ещё один распространённый случай — тег select для объекта, связанного через belongs_to.
Пример с
@post.person_id => 2:select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: "None" })может превратиться в:
<select name="post[person_id]" id="post_person_id"> <option value="">None</option> <option value="1">David</option> <option value="2" selected="selected">Eileen</option> <option value="3">Rafael</option> </select>
-
:prompt— задайте значение true или строку-подсказку. Если у элемента select ещё нет значения, перед ним добавляется параметр с общей подсказкой — «Выберите» — или указанной строкой-подсказкой.select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { prompt: "Select Person" })может превратиться в:
<select name="post[person_id]" id="post_person_id"> <option value="">Select Person</option> <option value="1">David</option> <option value="2">Eileen</option> <option value="3">Rafael</option> </select>
-
:index— как и другие помощники форм,selectпринимает параметр:index, позволяющий вручную задать идентификатор, используемый в результирующем выводе. В отличие от других помощников,selectожидает этот параметр в параметреhtml_options.select("album[]", :genre, %w[ rap rock country ], {}, { index: nil })превращается в:
<select name="album[][genre]" id="album__genre"> <option value="rap">rap</option> <option value="rock">rock</option> <option value="country">country</option> </select>
-
:disabled— может быть отдельным значением или массивом значений, соответствующих отключённым параметрам в итоговом выводе.select(:post, :category, Post::CATEGORIES, { disabled: "restricted" })может превратиться в:
<select name="post[category]" id="post_category"> <option value="joke">joke</option> <option value="poem">poem</option> <option disabled="disabled" value="restricted">restricted</option> </select>
При использовании с помощником
collection_select:disabledтакже может быть Proc, определяющим параметры, которые следует отключить.collection_select(:post, :category_id, Category.all, :id, :name, { disabled: -> (category) { category.archived? } })Если для категорий «материалы 2008 года» и «Рождество» метод
archived?возвращает true, результат будет таким:<select name="post[category_id]" id="post_category_id"> <option value="1" disabled="disabled">2008 stuff</option> <option value="2" disabled="disabled">Christmas</option> <option value="3">Jokes</option> <option value="4">Poems</option> </select>
Открытые методы экземпляра
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 784
def collection_checkboxes(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)
Tags::CollectionCheckBoxes.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block)
end Возвращает теги флажков для коллекции существующих возвращаемых значений method класса object. Будет выбран результат вызова method для экземпляра object. Если вызов method возвращает nil, выбор не производится.
Параметры :value_method и :text_method — это методы, вызываемые для каждого элемента collection. Их возвращаемые значения используются соответственно в качестве атрибута value и содержимого каждого тега флажка. Также это может быть любой объект, отвечающий на call, например proc, который будет вызван для каждого элемента collection, чтобы получить значение/текст.
Пример структуры объекта для использования с этим методом:
class Post < ActiveRecord::Base
has_and_belongs_to_many :authors
end
class Author < ActiveRecord::Base
has_and_belongs_to_many :posts
def name_with_initial
"#{first_name.first}. #{last_name}"
end
end
Пример использования (выбор связанного автора для экземпляра Post, @post):
collection_checkboxes(:post, :author_ids, Author.all, :id, :name_with_initial)
Если @post.author_ids уже имеет значение [1], результат будет таким:
<input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" checked="checked" /> <label for="post_author_ids_1">D. Heinemeier Hansson</label> <input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" /> <label for="post_author_ids_2">D. Thomas</label> <input id="post_author_ids_3" name="post[author_ids][]" type="checkbox" value="3" /> <label for="post_author_ids_3">M. Clark</label> <input name="post[author_ids][]" type="hidden" value="" />
Также можно настроить отображение элементов, передав методу блок:
collection_checkboxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b|
b.label { b.checkbox }
end
Аргумент, передаваемый блоку, — это специальный тип построителя для этой коллекции, который умеет создавать метку и флажок для текущего элемента коллекции с соответствующими текстом и значением. С его помощью можно изменить порядок отображения метки и флажка или даже использовать метку в качестве обёртки, как в примере выше.
Методы построителя label и checkbox также принимают дополнительные параметры HTML:
collection_checkboxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b|
b.label(class: "checkbox") { b.checkbox(class: "checkbox") }
end
Также доступны три специальных метода: object, text и value, которые соответственно возвращают текущий отображаемый элемент, его текст и значение. Их можно использовать так:
collection_checkboxes(:post, :author_ids, Author.all, :id, :name_with_initial) do |b|
b.label(:"data-value" => b.value) { b.checkbox + b.text }
end
Особый случай
Если для коллекции флажков ничего не выбрано, большинство веб-браузеров не отправляют никакого значения.
Например, если у нас есть модель User с полем category_ids и в действии update используется следующий код:
@user.update(params[:user])
Если не выбрано ни одного category_ids, можно смело предположить, что это поле не будет обновлено.
Это возможно благодаря скрытому полю, которое вспомогательный метод создаёт для каждой коллекции флажков. Этому скрытому полю присваивается то же имя, что и флажкам, а его значение остаётся пустым.
В редких случаях, когда это скрытое поле не нужно, можно передать вспомогательному методу параметр include_hidden: false.
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 700
def collection_radio_buttons(object, method, collection, value_method, text_method, options = {}, html_options = {}, &block)
Tags::CollectionRadioButtons.new(object, method, self, collection, value_method, text_method, options, html_options).render(&block)
end Возвращает теги переключателей для коллекции существующих возвращаемых значений method класса object. Будет выбран результат вызова method для экземпляра object. Если вызов method возвращает nil, выбор не производится.
Параметры :value_method и :text_method — это методы, вызываемые для каждого элемента collection. Их возвращаемые значения используются соответственно в качестве атрибута value и содержимого каждого тега переключателя. Также это может быть любой объект, отвечающий на call, например proc, который будет вызван для каждого элемента collection, чтобы получить значение/текст.
Пример структуры объекта для использования с этим методом:
class Post < ActiveRecord::Base
belongs_to :author
end
class Author < ActiveRecord::Base
has_many :posts
def name_with_initial
"#{first_name.first}. #{last_name}"
end
end
Пример использования (выбор связанного автора для экземпляра Post, @post):
collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial)
Если @post.author_id уже имеет значение 1, результат будет таким:
<input id="post_author_id_1" name="post[author_id]" type="radio" value="1" checked="checked" /> <label for="post_author_id_1">D. Heinemeier Hansson</label> <input id="post_author_id_2" name="post[author_id]" type="radio" value="2" /> <label for="post_author_id_2">D. Thomas</label> <input id="post_author_id_3" name="post[author_id]" type="radio" value="3" /> <label for="post_author_id_3">M. Clark</label>
Также можно настроить отображение элементов, передав методу блок:
collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b|
b.label { b.radio_button }
end
Аргумент, передаваемый блоку, — это специальный тип построителя для этой коллекции, который умеет создавать метку и переключатель для текущего элемента коллекции с соответствующими текстом и значением. С его помощью можно изменить порядок отображения метки и переключателя или даже использовать метку в качестве обёртки, как в примере выше.
Методы построителя label и radio_button также принимают дополнительные параметры HTML:
collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b|
b.label(class: "radio_button") { b.radio_button(class: "radio_button") }
end
Также доступны три специальных метода: object, text и value, которые соответственно возвращают текущий отображаемый элемент, его текст и значение. Их можно использовать так:
collection_radio_buttons(:post, :author_id, Author.all, :id, :name_with_initial) do |b|
b.label(:"data-value" => b.value) { b.radio_button + b.text }
end
Особый случай
Согласно спецификации HTML, если в коллекции переключателей ничего не выбрано, веб-браузеры не отправляют на сервер никакого значения. К сожалению, это создаёт проблему: если у модели User есть поле category_id и в форме не выбрана ни одна категория, параметр category_id не отправляется. Поэтому любой идиоматический код для строгих параметров вроде:
params.expect(user: [...])
вызовет ошибку, поскольку {user: ...} не будет задан.
Чтобы этого избежать, вспомогательный метод создаёт вспомогательное скрытое поле перед каждой коллекцией переключателей. У скрытого поля такое же имя, как у коллекции переключателей, а его значение пустое.
Если вы не хотите, чтобы вспомогательный метод создавал это скрытое поле, укажите параметр include_hidden: false.
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 198
def collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})
Tags::CollectionSelect.new(object, method, self, collection, value_method, text_method, options, html_options).render
end Возвращает теги <select> и <option> для коллекции существующих возвращаемых значений method класса object. Будет выбран результат вызова method для экземпляра object. Если вызов method возвращает nil, выбор не производится, если в хэш options не включить :prompt или :include_blank.
Параметры :value_method и :text_method — это методы, вызываемые для каждого элемента collection. Их возвращаемые значения используются соответственно в качестве атрибута value и содержимого каждого тега <option>. Также это может быть любой объект, отвечающий на call, например proc, который будет вызван для каждого элемента collection, чтобы получить значение/текст.
Пример структуры объекта для использования с этим методом:
class Post < ActiveRecord::Base
belongs_to :author
end
class Author < ActiveRecord::Base
has_many :posts
def name_with_initial
"#{first_name.first}. #{last_name}"
end
end
Пример использования (выбор связанного автора для экземпляра Post, @post):
collection_select(:post, :author_id, Author.all, :id, :name_with_initial, prompt: true)
Если @post.author_id уже имеет значение 1, результат будет таким:
<select name="post[author_id]" id="post_author_id"> <option value="">Please select</option> <option value="1" selected="selected">D. Heinemeier Hansson</option> <option value="2">D. Thomas</option> <option value="3">M. Clark</option> </select>
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 257
def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
Tags::GroupedCollectionSelect.new(object, method, self, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options).render
end Возвращает теги <select>, <optgroup> и <option> для коллекции существующих возвращаемых значений method класса object. Будет выбран результат вызова method для экземпляра object. Если вызов method возвращает nil, выбор не производится, если в хэш options не включить :prompt или :include_blank.
Параметры:
-
object— экземпляр класса, используемый для тега select -
method— атрибутobject, соответствующий тегу select -
collection— массив объектов, представляющих теги<optgroup>. -
group_method— имя метода, который при вызове для элементаcollectionвозвращает массив дочерних объектов, представляющих теги<option>. Также это может быть любой объект, отвечающий наcall, напримерproc, который будет вызван для каждого элементаcollection, чтобы получить значение. -
group_label_method— имя метода, который при вызове для элементаcollectionвозвращает строку, используемую в качестве атрибутаlabelдля его тега<optgroup>. Также это может быть любой объект, отвечающий наcall, напримерproc, который будет вызван для каждого элементаcollection, чтобы получить метку. -
option_key_method— имя метода, который при вызове для дочернего объекта элементаcollectionвозвращает значение, используемое в качестве атрибутаvalueдля его тега<option>. -
option_value_method— имя метода, который при вызове для дочернего объекта элементаcollectionвозвращает значение, используемое в качестве содержимого его тега<option>.
Пример структуры объекта для использования с этим методом:
# attributes: id, name class Continent < ActiveRecord::Base has_many :countries end # attributes: id, name, continent_id class Country < ActiveRecord::Base belongs_to :continent end # attributes: id, name, country_id class City < ActiveRecord::Base belongs_to :country end
Пример использования:
grouped_collection_select(:city, :country_id, @continents, :countries, :name, :id, :name)
Возможный результат:
<select name="city[country_id]" id="city_country_id">
<optgroup label="Africa">
<option value="1">South Africa</option>
<option value="3">Somalia</option>
</optgroup>
<optgroup label="Europe">
<option value="7" selected="selected">Denmark</option>
<option value="2">Ireland</option>
</optgroup>
</select> # File actionview/lib/action_view/helpers/form_options_helper.rb, line 535
def grouped_options_for_select(grouped_options, selected_key = nil, options = {})
prompt = options[:prompt]
divider = options[:divider]
body = "".html_safe
if prompt
body.safe_concat content_tag("option", prompt_text(prompt), value: "")
end
grouped_options.each do |container|
html_attributes = option_html_attributes(container)
if divider
label = divider
else
label, container = container
end
html_attributes = { label: label }.merge!(html_attributes)
body.safe_concat content_tag("optgroup", options_for_select(container, selected_key), html_attributes)
end
body
end Возвращает строку с тегами <option>, как options_for_select, но оборачивает их в теги <optgroup>:
grouped_options = [
['North America',
[['United States','US'],'Canada']],
['Europe',
['Denmark','Germany','France']]
]
grouped_options_for_select(grouped_options)
grouped_options = {
'North America' => [['United States','US'], 'Canada'],
'Europe' => ['Denmark','Germany','France']
}
grouped_options_for_select(grouped_options)
Возможный результат:
<optgroup label="North America"> <option value="US">United States</option> <option value="Canada">Canada</option> </optgroup> <optgroup label="Europe"> <option value="Denmark">Denmark</option> <option value="Germany">Germany</option> <option value="France">France</option> </optgroup>
Параметры
-
grouped_options— принимает вложенный массив или хэш строк. Первое значение служит меткой<optgroup>, а второе должно быть массивом вариантов. Второе значение может быть вложенным массивом пар текст-значение. Подробнее см. в разделеoptions_for_select.Ex. ["North America",[["United States","US"],["Canada","CA"]]]
В качестве необязательного третьего значения можно передать атрибуты HTML для
optgroup.Ex. ["North America",[["United States","US"],["Canada","CA"]], { disabled: "disabled" }] -
selected_key— значение, совпадающее с атрибутомvalueодного из тегов<option>; для этого тега будет установлен атрибутselected. Примечание: это значение может совпадать с несколькими вариантами, если один и тот же вариант присутствует в нескольких группах. Тогда атрибутselected="selected"будет установлен для каждого из них.
Параметры
-
:prompt— установите значение true или строку-подсказку. Если у элемента select ещё нет значения, перед вариантами добавляется вариант с общей подсказкой «Выберите» или с указанной строкой-подсказкой. -
:divider— разделитель групп вариантов.grouped_options = [ [['United States','US'], 'Canada'], ['Denmark','Germany','France'] ] grouped_options_for_select(grouped_options, nil, divider: '---------')
Возможный результат:
<optgroup label="---------"> <option value="US">United States</option> <option value="Canada">Canada</option> </optgroup> <optgroup label="---------"> <option value="Denmark">Denmark</option> <option value="Germany">Germany</option> <option value="France">France</option> </optgroup>
Примечание: Возвращаются только теги <optgroup> и <option>, поэтому результат необходимо обернуть в соответствующий тег <select>.
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 461
def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil)
collection.map do |group|
option_tags = options_from_collection_for_select(
value_for_collection(group, group_method), option_key_method, option_value_method, selected_key)
content_tag("optgroup", option_tags, label: value_for_collection(group, group_label_method))
end.join.html_safe
end Возвращает строку с тегами <option>, как options_from_collection_for_select, но группирует их с помощью тегов <optgroup> на основе взаимосвязей между объектами, заданных аргументами.
Параметры:
-
collection— массив объектов, представляющих теги<optgroup>. -
group_method— имя метода, который при вызове для элементаcollectionвозвращает массив дочерних объектов, представляющих теги<option>. -
group_label_method— имя метода, который при вызове для элементаcollectionвозвращает строку, используемую в качестве атрибутаlabelдля его тега<optgroup>. -
option_key_method— имя метода, который при вызове для дочернего объекта элементаcollectionвозвращает значение, используемое в качестве атрибутаvalueдля его тега<option>. -
option_value_method— имя метода, который при вызове для дочернего объекта элементаcollectionвозвращает значение, используемое в качестве содержимого его тега<option>. -
selected_key— значение, совпадающее с атрибутомvalueодного из тегов<option>; для этого тега будет установлен атрибутselected. Соответствует возвращаемому значению одного из вызововoption_key_method. Если заданоnil, выбор не производится. Также может быть хэшем, если нужно указать отключённые значения.
Пример структуры объекта для использования с этим методом:
class Continent < ActiveRecord::Base has_many :countries # attribs: id, name end class Country < ActiveRecord::Base belongs_to :continent # attribs: id, name, continent_id end
Пример использования:
option_groups_from_collection_for_select(@continents, :countries, :name, :id, :name, 3)
Возможный результат:
<optgroup label="Africa"> <option value="1">Egypt</option> <option value="4">Rwanda</option> ... </optgroup> <optgroup label="Asia"> <option value="3" selected="selected">China</option> <option value="12">India</option> <option value="5">Japan</option> ... </optgroup>
Примечание: Возвращаются только теги <optgroup> и <option>, поэтому результат необходимо обернуть в соответствующий тег <select>.
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 357
def options_for_select(container, selected = nil)
return container if String === container
selected, disabled = extract_selected_and_disabled(selected).map do |r|
Array(r).map(&:to_s)
end
container.map do |element|
html_attributes = option_html_attributes(element)
text, value = option_text_and_value(element).map(&:to_s)
html_attributes[:selected] ||= option_value_selected?(value, selected)
html_attributes[:disabled] ||= disabled && option_value_selected?(value, disabled)
html_attributes[:value] = value
tag_builder.option(text, **html_attributes)
end.join("\n").html_safe
end Принимает контейнер (хэш, массив, перечислимый объект или объект вашего типа) и возвращает строку с тегами вариантов. Если элементы контейнера отвечают на first и last (например, это двухэлементный массив), «последние» значения используются как значения вариантов, а «первые» — как текст вариантов. Хэши автоматически преобразуются в такой формат: ключи становятся «первыми» значениями, а значения — последними. Если задан параметр selected, соответствующий «последний» элемент или значение получит тег выбранного варианта. selected также может быть массивом значений, которые нужно выбрать при использовании множественного выбора.
options_for_select([["Dollar", "$"], ["Kroner", "DKK"]])
# => <option value="$">Dollar</option>
# => <option value="DKK">Kroner</option>
options_for_select([ "VISA", "MasterCard" ], "MasterCard")
# => <option value="VISA">VISA</option>
# => <option selected="selected" value="MasterCard">MasterCard</option>
options_for_select({ "Basic" => "$20", "Plus" => "$40" }, "$40")
# => <option value="$20">Basic</option>
# => <option value="$40" selected="selected">Plus</option>
options_for_select([ "VISA", "MasterCard", "Discover" ], ["VISA", "Discover"])
# => <option selected="selected" value="VISA">VISA</option>
# => <option value="MasterCard">MasterCard</option>
# => <option selected="selected" value="Discover">Discover</option>
В качестве последнего элемента массива можно указать атрибуты HTML.
options_for_select([ "Denmark", ["USA", { class: 'bold' }], "Sweden" ], ["USA", "Sweden"])
# => <option value="Denmark">Denmark</option>
# => <option value="USA" class="bold" selected="selected">USA</option>
# => <option value="Sweden" selected="selected">Sweden</option>
options_for_select([["Dollar", "$", { class: "bold" }], ["Kroner", "DKK", { onclick: "alert('HI');" }]])
# => <option value="$" class="bold">Dollar</option>
# => <option value="DKK" onclick="alert('HI');">Kroner</option>
Чтобы указать отключённые варианты, задайте selected в виде хэша, где :disabled — значение или массив значений, которые нужно отключить. В этом случае для указания выбранных тегов вариантов можно использовать :selected.
options_for_select(["Free", "Basic", "Advanced", "Super Platinum"], disabled: "Super Platinum") # => <option value="Free">Free</option> # => <option value="Basic">Basic</option> # => <option value="Advanced">Advanced</option> # => <option value="Super Platinum" disabled="disabled">Super Platinum</option> options_for_select(["Free", "Basic", "Advanced", "Super Platinum"], disabled: ["Advanced", "Super Platinum"]) # => <option value="Free">Free</option> # => <option value="Basic">Basic</option> # => <option value="Advanced" disabled="disabled">Advanced</option> # => <option value="Super Platinum" disabled="disabled">Super Platinum</option> options_for_select(["Free", "Basic", "Advanced", "Super Platinum"], selected: "Free", disabled: "Super Platinum") # => <option value="Free" selected="selected">Free</option> # => <option value="Basic">Basic</option> # => <option value="Advanced">Advanced</option> # => <option value="Super Platinum" disabled="disabled">Super Platinum</option>
ПРИМЕЧАНИЕ: Возвращаются только теги вариантов; этот вызов необходимо обернуть в обычный тег HTML select.
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 400
def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
options = collection.map do |element|
[value_for_collection(element, text_method), value_for_collection(element, value_method), option_html_attributes(element)]
end
selected, disabled = extract_selected_and_disabled(selected)
select_deselect = {
selected: extract_values_from_collection(collection, value_method, selected),
disabled: extract_values_from_collection(collection, value_method, disabled)
}
options_for_select(options, select_deselect)
end Возвращает строку с тегами вариантов, созданными путём перебора collection и присвоения результату вызова value_method значения варианта, а text_method — его текста.
options_from_collection_for_select(@people, 'id', 'name')
# => <option value="#{person.id}">#{person.name}</option>
Чаще всего этот метод используется внутри select_tag, как в следующем примере:
select_tag 'person', options_from_collection_for_select(@people, 'id', 'name')
Если selected задано как значение или массив значений, элементам, для которых value_method возвращает совпадение, будут соответствовать выбранные теги вариантов.
Если selected задан как Proc, выбранными значениями будут элементы коллекции, для которых анонимная функция возвращает true.
selected также может быть хэшем, задающим значения :selected и/или :disabled.
При указании выбранных или отключённых вариантов обязательно используйте тот же класс, что и у value_method. Иначе результат будет неверным. Пример:
options_from_collection_for_select(@people, 'id', 'name', '1')
не выберет человека с идентификатором 1, потому что 1 (Integer) — это не то же самое, что «1» (строка)
options_from_collection_for_select(@people, 'id', 'name', 1)
должен дать ожидаемый результат.
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 158
def select(object, method, choices = nil, options = {}, html_options = {}, &block)
Tags::Select.new(object, method, self, choices, options, html_options, &block).render
end Создаёт тег select и содержащуюся в нём последовательность тегов вариантов для заданных объекта и метода. Если объект доступен, будет выбран текущий вариант, хранящийся в нём.
Параметр choices допускает два формата, соответствующих результатам других вспомогательных методов:
-
Плоская коллекция (см.
options_for_select). -
Вложенная коллекция (см.
grouped_options_for_select).
Пример с @post.person_id => 2:
select :post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true }
превратится в:
<select name="post[person_id]" id="post_person_id"> <option value="" label=" "></option> <option value="1">David</option> <option value="2" selected="selected">Eileen</option> <option value="3">Rafael</option> </select>
Это можно использовать, чтобы стандартным способом предоставить набор вариантов по умолчанию: перед отображением формы создания новому экземпляру модели назначаются варианты по умолчанию, и он привязывается к @model_name. Обычно эта модель не сохраняется в базе данных. Вместо этого при получении запроса на создание создаётся второй объект модели. Это позволяет пользователю отправить страницу формы несколько раз и получить ожидаемый результат — создать несколько записей. Кроме того, так можно использовать один partial для создания полей формы как редактирования, так и создания.
По умолчанию выбран вариант post.person_id. Укажите selected: value, чтобы выбрать другой вариант, или selected: nil, чтобы оставить все варианты невыбранными. Аналогично, можно указать отключаемые варианты в тегах вариантов с помощью параметра :disabled. Это может быть одно значение или массив значений, которые нужно отключить.
В select можно передать блок, чтобы настроить отображение тегов вариантов. Это удобно, если тег варианта имеет сложные атрибуты.
select(report, :campaign_ids) do
available_campaigns.each do |c|
tag.option(c.name, value: c.id, data: { tags: c.tags.to_json })
end
end
Особый случай
Согласно спецификации HTML, если параметру multiple передано значение select и все варианты сняты, веб-браузеры не отправляют на сервер никакого значения. К сожалению, это создаёт проблему: если у модели User есть несколько roles и аксессор role_ids, а в форме редактирования ролей пользователь снимает все роли в поле множественного выбора role_ids, параметр role_ids не отправляется. Поэтому любой идиоматический код массового присваивания вроде
@user.update(params[:user])
не обновит роли.
Чтобы этого избежать, вспомогательный метод создаёт вспомогательное скрытое поле перед каждым элементом множественного выбора. У скрытого поля такое же имя, как у поля множественного выбора, а его значение пустое.
Примечание: Клиент отправляет либо только скрытое поле (представляющее поле множественного выбора без выбранных вариантов), либо оба поля. Это означает, что результирующий массив всегда содержит пустую строку.
Если вы не хотите, чтобы вспомогательный метод создавал это скрытое поле, укажите параметр include_hidden: false.
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 580
def time_zone_options_for_select(selected = nil, priority_zones = nil, model = ::ActiveSupport::TimeZone)
zone_options = "".html_safe
zones = model.all
convert_zones = lambda { |list| list.map { |z| [ z.to_s, z.name ] } }
if priority_zones
if priority_zones.is_a?(Regexp)
priority_zones = zones.select { |z| z.match?(priority_zones) }
end
zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected)
zone_options.safe_concat content_tag("option", "-------------", value: "", disabled: true)
zone_options.safe_concat "\n"
zones = zones - priority_zones
end
zone_options.safe_concat options_for_select(convert_zones[zones], selected)
end Возвращает строку с тегами вариантов для практически любого часового пояса в мире. Передайте имя ActiveSupport::TimeZone в качестве selected, чтобы пометить его тег варианта как выбранный. Также можно передать массив объектов ActiveSupport::TimeZone в качестве priority_zones, чтобы они отображались перед остальными элементами длинного списка. (Для удобства получения списка часовых поясов США можно использовать ActiveSupport::TimeZone.us_zones, а для выбора нужных поясов — Regexp.)
Параметр selected должен иметь значение nil или быть строкой, задающей имя ActiveSupport::TimeZone.
По умолчанию model — это константа ActiveSupport::TimeZone (в Active Record её можно получить как объект-значение). Параметр model должен отвечать на all и возвращать массив объектов, представляющих часовые пояса; каждый объект должен отвечать на name. Если передано Regexp, для сопоставления часовых поясов будет использоваться метод match?.
ПРИМЕЧАНИЕ: Возвращаются только теги вариантов; этот вызов необходимо обернуть в обычный тег HTML select.
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 291
def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
Tags::TimeZoneSelect.new(object, method, self, priority_zones, options, html_options).render
end Возвращает теги select и вариантов для заданных объекта и метода, используя time_zone_options_for_select для создания списка тегов вариантов.
Помимо описанного выше параметра :include_blank, этот метод также поддерживает параметр :model, по умолчанию равный ActiveSupport::TimeZone. С его помощью можно указать другой объект модели часового пояса. (Подробнее см. в разделе time_zone_options_for_select.)
Также можно передать массив объектов ActiveSupport::TimeZone в качестве priority_zones, чтобы они отображались перед остальными элементами длинного списка. Для получения списка часовых поясов США можно использовать ActiveSupport::TimeZone.us_zones, часовых поясов другой страны — ActiveSupport::TimeZone.country_zones(country_code), а для выбора нужных поясов — Regexp.
Наконец, этот метод поддерживает параметр :default, который выбирает часовой пояс ActiveSupport::TimeZone по умолчанию, если часовой пояс объекта равен nil.
time_zone_select(:user, :time_zone, nil, include_blank: true) time_zone_select(:user, :time_zone, nil, default: "Pacific Time (US & Canada)") time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)") time_zone_select(:user, :time_zone, [ ActiveSupport::TimeZone["Alaska"], ActiveSupport::TimeZone["Hawaii"] ]) time_zone_select(:user, :time_zone, /Australia/) time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 613
def weekday_options_for_select(selected = nil, index_as_value: false, day_format: :day_names, beginning_of_week: Date.beginning_of_week)
day_names = I18n.translate("date.#{day_format}")
day_names = day_names.map.with_index.to_a if index_as_value
day_names = day_names.rotate(Date::DAYS_INTO_WEEK.fetch(beginning_of_week))
options_for_select(day_names, selected)
end Возвращает строку с тегами вариантов для дней недели.
Параметры
-
:index_as_value— по умолчанию false; задайте true, чтобы использовать индексы изI18n.translate("date.day_names")в качестве значений. По умолчанию воскресенье всегда имеет значение 0. -
:day_format— ключ I18n массива, используемого для вариантов дней недели. По умолчанию:day_names; задайте:abbr_day_names, чтобы использовать сокращения. -
:beginning_of_week— по умолчаниюDate.beginning_of_week.
ПРИМЕЧАНИЕ: Возвращаются только теги вариантов; этот вызов необходимо обернуть в обычный тег HTML select.
# File actionview/lib/action_view/helpers/form_options_helper.rb, line 297
def weekday_select(object, method, options = {}, html_options = {}, &block)
Tags::WeekdaySelect.new(object, method, self, options, html_options, &block).render
end Возвращает теги select и вариантов для заданных объекта и метода, используя weekday_options_for_select для создания списка тегов вариантов.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.