Estoy usando Rails 3.2.0.rc2 . Tengo una Model
, en la que tengo una estática Array
que ofrezco a través de un formulario de modo que los usuarios pueden seleccionar un subconjunto Array
y guardar su selección en la base de datos, almacenada en una sola columna en formato Model
. He usado serializar en la columna de la base de datos que almacena Array
y Rails está convirtiendo correctamente las selecciones de los usuarios en Yaml (y de vuelta a una matriz al leer esa columna). Estoy usando una entrada de formulario de selección múltiple para hacer selecciones.
Mi problema es que, tal como lo tengo actualmente, todo funciona como esperaba, excepto que la matriz de subconjuntos del usuario siempre tiene un primer elemento en blanco cuando se envía al servidor.
Esto no es gran cosa, y podría escribir código para eliminar eso después del hecho, pero siento que solo estoy cometiendo algún tipo de error sintáctico, ya que no me parece que el comportamiento predeterminado de Rails lo haría intencionalmente. agregue este elemento en blanco sin alguna razón. Debo haberme perdido algo o haberme olvidado de desactivar algún tipo de configuración. Ayúdeme a comprender lo que me falta (o indíqueme alguna buena documentación que describa esto con más profundidad de lo que he podido encontrar en los intertubos).
'Modelos' de tablas de base de datos MySQL:
- incluye una columna denominada
subset_array
que es un campo de TEXTO
El modelo de clase incluye las siguientes configuraciones:
serialize :subset_array
ALL_POSSIBLE_VALUES = [value1, value2, value3, ...]
El formulario para editar modelos incluye la siguiente opción de entrada:
f.select :subset_array, Model::ALL_POSSIBLE_VALUES, {}, :multiple => true, :selected => @model.subset_array
PUT al servidor desde el cliente se parece a esto:
- asumiendo que solo se seleccionan value1 y value3
"model" => { "subset_array" => ["", value1, value3] }
La actualización de la base de datos tiene este aspecto:
UPDATE 'models' SET 'subset_array' = '--- \n- \"\"\n- value1\n- value3\n'
Como puede ver, hay un elemento en blanco adicional en la matriz que se envía y configura en la base de datos. ¿Cómo me deshago de eso? ¿Hay algún parámetro que me falta en mi f.select
llamada?
Muchas gracias apreciado :)
EDITAR : Este es el código HTML generado a partir de la f.select
declaración. ¿Parece que se está generando una entrada oculta que puede ser la causa de mi problema? ¿Por qué está ahí?
<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>
fuente
f.select
está generando? Además, ¿este comportamiento ocurre incluso en la creación o solo en la actualización?f.select
include_hidden: false
vienen con un problema. Cuando eliminas todos los valores del cuadro de selección, la expresión idiomáticamodel.update(something_params)
no incluirá ese campo. TL; DR no podrá dejar el campo vacío.Respuestas:
El campo oculto es lo que está causando el problema. Pero está ahí por una buena razón: cuando todos los valores están deseleccionados, aún recibe un parámetro subset_array. De los documentos de Rails (es posible que deba desplazarse hacia la derecha para ver todo esto):
# 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.
EDITAR: El último párrafo sugiere que no debería ver el vacío en el caso cuando se selecciona algo, pero creo que está mal. La persona que hizo este compromiso con Rails (consulte https://github.com/rails/rails/commit/faba406fa15251cdc9588364d23c687a14ed6885 ) está tratando de hacer el mismo truco que usa Rails para las casillas de verificación (como se menciona aquí: https://github.com / rails / rails / pull / 1552 ), pero no creo que pueda funcionar para un cuadro de selección múltiple porque los parámetros enviados forman una matriz en este caso y, por lo tanto, no se ignora ningún valor.
Entonces mi sensación es que esto es un error.
fuente
En Rails 4:
Podrás aprobar la
:include_hidden
opción. https://github.com/rails/rails/pull/5414/filesComo solución rápida por ahora: puede usar ahora mismo en su modelo:
before_validation do |model| model.subset_array.reject!(&:blank?) if model.subset_array end
Esto simplemente eliminará todos los valores en blanco a nivel de modelo.
fuente
En Rails 4+ set: include_hidden en select_tag a falso
<%= form.grouped_collection_select :employee_id, Company.all, :employees, :name, :id, :name, { include_hidden: false }, { size: 6, multiple: true } %>
fuente
Otra solución rápida es usar este filtro de controlador:
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
De esta forma, se puede reutilizar en los controladores sin tocar la capa del modelo.
fuente
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-check_box
Para eliminar valores en blanco:
def myfield=(value) value.reject!(&:blank?) write_attribute(:myfield, value) end
fuente
En el controlador:
arr = arr.delete_if { |x| x.empty? }
fuente
Lo arreglé usando el
params[:review][:staff_ids].delete("")
en el controlador antes de la actualización.En mi vista:
= form_for @review do |f| = f.collection_select :staff_ids, @business.staff, :id, :full_name, {}, {multiple:true} = f.submit 'Submit Review'
En mi controlador:
class ReviewsController < ApplicationController def create .... params[:review][:staff_ids].delete("") @review.update_attribute(:staff_ids, params[:review][:staff_ids].join(",")) .... end end
fuente
Lo hago funcionar escribiendo esto en la parte de Javascript de la página:
$("#model_subset_array").val( <%= @model.subset_array %> );
El mío se parece más a lo siguiente:
$("#modela_modelb_ids").val( <%= @modela.modelb_ids %> );
No estoy seguro de si esto me va a dar dolor de cabeza en el futuro, pero ahora funciona bien.
fuente
Utilice jQuery:
$('select option:empty').remove();
Opción para eliminar las opciones en blanco del menú desplegable.
fuente