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

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

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

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

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

  • включает столбец с именем subset_array, который является полем TEXT

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

    serialize :subset_array литий> ALL_POSSIBLE_VALUES = [value1, value2, value3, ...] литий>

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

    f.select :subset_array, Model::ALL_POSSIBLE_VALUES, {}, :multiple => true, :selected => @model.subset_array литий>

PUT на сервер от клиента выглядит примерно так:

  • при условии, что выбраны только value1 и value3
  • "model" => { "subset_array" => ["", value1, value3] } литий>

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

    UPDATE 'models' SET 'subset_array' = '--- \n- \"\"\n- value1\n- value3\n' литий>

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

Большое спасибо, оценили:)

РЕДАКТИРОВАТЬ . Это сгенерированный 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>
78 голосов | спросил robmclarty 19 Jpm1000000pmThu, 19 Jan 2012 20:02:38 +040012 2012, 20:02:38

9 ответов


0

Скрытое поле является причиной проблемы. Но для этого есть веская причина: когда все значения отменены, вы все равно получаете параметр 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.

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

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

ответил Mike A. 20 Jam1000000amFri, 20 Jan 2012 00:50:02 +040012 2012, 00:50:02
0

В Rails 4:

Вы сможете передать параметр :include_hidden. https://github.com/rails/rails/pull/5414/files

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

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

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

ответил Bogdan Gusiev 20 Jpm1000000pmFri, 20 Jan 2012 13:27:45 +040012 2012, 13:27:45
0

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

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

Этот способ можно повторно использовать на контроллерах, не касаясь слоя модели.

ответил Max 31 Jpm1000000pmTue, 31 Jan 2012 23:21:03 +040012 2012, 23:21:03
0

http://api.rubyonrails.org/классы /ActionView /хелперы /FormHelper.html # метод-я-check_box

  

Гоча

     

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

     

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

     

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

     

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

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

  def myfield=(value)
    value.reject!(&:blank?)
    write_attribute(:myfield, value)
  end
ответил devishot 3 AMpThu, 03 Apr 2014 09:25:49 +040025Thursday 2014, 09:25:49
0

В Rails 4+ установите: include_hidden для select_tag равен false

<%= form.grouped_collection_select :employee_id, Company.all, :employees, :name, :id, :name, { include_hidden: false }, { size: 6, multiple: true } %>
ответил Martin 1 Maypm18 2018, 18:07:36
0

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

arr = arr.delete_if { |x| x.empty? }
ответил Mauro 18 Maypm12 2012, 20:34:13
0

Я исправил это, используя 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
ответил Bruno 14 +04002014-10-14T21:30:15+04:00312014bEurope/MoscowTue, 14 Oct 2014 21:30:15 +0400 2014, 21:30:15
0

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

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

Шахта выглядит примерно так:

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

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

ответил imaginabit 12 FebruaryEurope/MoscowbTue, 12 Feb 2013 00:35:50 +0400000000amTue, 12 Feb 2013 00:35:50 +040013 2013, 00:35:50
0

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

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

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

ответил user1875926 4 PMpThu, 04 Apr 2013 17:36:34 +040036Thursday 2013, 17:36:34

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132