Почему первый элемент всегда пуст в моем Rails multi-select, используя встроенный массив?


я использую рельсы 3.2.0.алгоритм RC2. У меня есть Model, в котором у меня статический!--2--> который я предлагаю через форму, чтобы пользователи могли выбрать подмножество Array и сохранить их выбор в базе данных, хранящейся в одном столбце в Model. Я использовал сериализацию в столбце базы данных, в котором хранится Array и Rails правильно преобразует выбор пользователей в Yaml (и обратно в массив при чтении этого столбца). Я использую мульти-выбор формы ввода делать выбор.

моя проблема заключается в том, что, как у меня сейчас есть, все работает так, как я ожидал бы, за исключением того, что массив подмножеств пользователя всегда имеет пустой первый элемент, когда он отправляется на сервер.

это не имеет большого значения, и я мог бы написать код, чтобы вырезать это после факта, но я чувствую, что я просто делаю какую-то синтаксическую ошибку, поскольку мне не кажется, что поведение Rails по умолчанию намеренно добавит это пустое место элемент без какой-либо причины. Должно быть, я что-то пропустил или забыл отключить какую-то настройку. Пожалуйста, помогите мне понять, что мне не хватает (или укажите мне на какую-нибудь хорошую документацию, которая описывает это с большей глубиной, чем то, что я смог найти на intertubes).

таблица базы данных MySQL 'models':

  • содержит столбец с именем subset_array который является текстовым полем

модель класса включает в себя следующие настройки:

  • serialize :subset_array
  • ALL_POSSIBLE_VALUES = [value1, value2, value3, ...]

форма для редактирования моделей включает в себя следующую опцию ввода:

  • f.select :subset_array, Model::ALL_POSSIBLE_VALUES, {}, :multiple => true, :selected => @model.subset_array

PUT to server from client выглядит примерно так:

  • предполагая, что выбраны только value1 и value3
  • "model" => { "subset_array" => ["", value1, value3] }

обновление базы данных выглядит как это:

  • UPDATE 'models' SET 'subset_array' = '--- n- ""n- value1n- value3n'

как вы можете видеть, есть этот лишний пустой элемент в массиве отправкой и установить в базе. Как мне от этого избавиться? Есть ли параметр, который я пропускаю из моего f.select звонок?

спасибо оценил :)

EDIT: это сгенерированный HTML код f.select заявление. Похоже, что существует скрытый ввод, который может быть причиной моего проблема? Почему это там?

<input name="model[subset_array][]" type="hidden" value>
<select id="model_subset_array" multiple="multiple" name="model[subset_array][]" selected="selected">
    <option value="value1" selected="selected">Value1</option>
    <option value="value2">Value2</option>
    <option value="value3" selected="selected">Value3</option>
    <option...>...</option>
</select>
9 77

9 ответов:

скрытое поле-это то, что вызывает проблему. Но это происходит по уважительной причине: когда все значения отменены, вы все равно получаете параметр subset_array. Из документов Rails (возможно, вам придется прокрутить вправо, чтобы увидеть все это):

  # The HTML specification says when +multiple+ parameter passed to select and all options got deselected
  # web browsers do not send any value to server. Unfortunately this introduces a gotcha:
  # if an +User+ model has many +roles+ and have +role_ids+ accessor, and in the form that edits roles of the user
  # the user deselects all roles from +role_ids+ multiple select box, no +role_ids+ parameter is sent. So,
  # any mass-assignment idiom like
  #
  #   @user.update_attributes(params[:user])
  #
  # wouldn't update roles.
  #
  # To prevent this the helper generates an auxiliary hidden field before
  # every multiple select. The hidden field has the same name as multiple select and blank value.
  #
  # This way, the client either sends only the hidden field (representing
  # the deselected multiple select box), or both fields. Since the HTML specification
  # says key/value pairs have to be sent in the same order they appear in the
  # form, and parameters extraction gets the last occurrence of any repeated
  # key in the query string, that works for ordinary forms.

EDIT: последний абзац предполагает, что вы не должны видеть пустой в случае, когда что-то выбрано, но я думаю, что это неправильно. Человек, который сделал эту фиксацию на Rails (см. https://github.com/rails/rails/commit/faba406fa15251cdc9588364d23c687a14ed6885) это пытается сделать тот же трюк, что рельсы использует для галочки (как уже упоминалось здесь: https://github.com/rails/rails/pull/1552), но я не думаю, что он может работать в течение нескольких выберите поле, потому что параметры, отправленные через форму массив в данном случае и поэтому никакого значения игнорируется.

Так что я чувствую, что это ошибка.

В Rails 4:

Вы сможете пройти . https://github.com/rails/rails/pull/5414/files

как быстрое решение на данный момент: Вы можете использовать прямо сейчас в вашей модели:

before_validation do |model|
  model.subset_array.reject!(&:blank?) if model.subset_array
end

Это просто удалить все пустые значения на уровне модели.

еще одно быстрое решение-использовать этот фильтр контроллера:

def clean_select_multiple_params hash = params
  hash.each do |k, v|
    case v
    when Array then v.reject!(&:blank?)
    when Hash then clean_select_multiple_params(v)
    end
  end
end

этот путь можно повторно использовать через регуляторы без касатьться модельному слою.

http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-check_box

понял

спецификация HTML говорит, что непроверенные флажки или выбор не являются успешными, и поэтому веб-браузеры не отправляют их. К сожалению, это вводит a gotcha: если модель счета-фактуры имеет оплаченный флаг, и в том виде, что редактирование оплаченного счета пользователь снимает флажок нет оплаты параметр передается. Так, любая идиома массового назначения, как

@накладной.обновление (params [: invoice]) не будет обновлять флаг.

чтобы предотвратить это помощник генерирует вспомогательное скрытое поле перед тот самый флажок. Скрытое поле имеет то же имя и его атрибуты имитируют непроверенный флажок.

таким образом, клиент либо отправляет только скрытое поле (представляющее флажок снят), или оба поля. Начиная с HTML спецификация говорит, что пары ключ/значение, должны быть отправлены в том же порядке они появляются в форме и извлечение параметров получает последний появление любого повторяющегося ключа в строке запроса, который работает для обычная форма.

удалить пустые значения:

  def myfield=(value)
    value.reject!(&:blank?)
    write_attribute(:myfield, value)
  end

в Rails 4 + set: include_hidden на select_tag в false

<%= form.grouped_collection_select :employee_id, Company.all, :employees, :name, :id, :name, { include_hidden: false }, { size: 6, multiple: true } %>

в контроллере:

arr = arr.delete_if { |x| x.empty? }

я исправил это с помощью params[:review][:staff_ids].delete("") в контроллере перед обновлением.

на мой взгляд:

= form_for @review do |f|
  = f.collection_select :staff_ids, @business.staff, :id, :full_name, {}, {multiple:true}
= f.submit 'Submit Review'

в моем контроллере:

class ReviewsController < ApplicationController
  def create
  ....
    params[:review][:staff_ids].delete("")
    @review.update_attribute(:staff_ids, params[:review][:staff_ids].join(","))
  ....
  end
end

Я заставляю его работать, написав это в Javascript части страницы:

$("#model_subset_array").val( <%= @model.subset_array %> );

мой выглядит следующим образом:

$("#modela_modelb_ids").val( <%= @modela.modelb_ids %> );

Не уверен, что это собирается получить меня головная боль в будущем, но сейчас он работает нормально.

использовать jQuery:

$('select option:empty').remove(); 

возможность удалить пустые параметры из выпадающего списка.