Pourquoi le premier élément est-il toujours vide dans mon multi-sélection Rails, en utilisant un tableau incorporé?

J’utilise Rails 3.2.0.rc2 . J’ai un Model dans lequel j’ai un Array statique que je propose via un formulaire, de sorte que les utilisateurs puissent sélectionner un sous-ensemble de Array et enregistrer leur sélection dans la firebase database, stockée dans une seule colonne dans Model . J’ai utilisé sérialiser sur la colonne de la firebase database qui stocke le Array et Rails convertit correctement les sélections des utilisateurs dans Yaml (et retourne à un tableau lors de la lecture de cette colonne). J’utilise une entrée de formulaire à sélection multiple pour effectuer des sélections.

Mon problème est que, comme je l’ai actuellement, tout fonctionne comme prévu, sauf que le tableau de sous-ensembles de l’utilisateur a toujours un premier élément vide lorsqu’il est envoyé au serveur.

Ce n’est pas un gros problème, et je pourrais écrire du code pour éviter cela, mais je pense que je fais juste une erreur de syntaxe car il ne me semble pas que le comportement par défaut de Rails serait intentionnel. ajoutez cet élément vide sans raison. J’ai dû manquer quelque chose ou j’ai oublié de désactiver une sorte de réglage. S’il vous plaît, aidez-moi à comprendre ce qui me manque (ou indiquez-moi une bonne documentation décrivant cela avec plus de profondeur que ce que j’ai pu trouver sur les intertubes).

MySQL Database Table ‘models’:

  • inclut une colonne nommée subset_array qui est un champ de subset_array

Le modèle de classe inclut les parameters suivants:

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

Le formulaire de modification des modèles comprend l’option de saisie suivante:

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

PUT to server du client ressemble à ceci:

  • en supposant que seulement valeur1 et valeur3 sont sélectionnés
  • "model" => { "subset_array" => ["", value1, value3] }

La mise à jour de la firebase database ressemble à ceci:

  • UPDATE 'models' SET 'subset_array' = '--- \n- \"\"\n- value1\n- value3\n'

Comme vous pouvez le voir, il y a cet élément supplémentaire, vide, dans le tableau envoyé et défini dans la firebase database. Comment puis-je m’en débarrasser? Y at-il un paramètre qui me manque dans mon appel f.select ?

Merci beaucoup apprécié 🙂

EDIT : Ceci est le code HTML généré par l’instruction f.select . Il semble qu’il y ait une entrée cachée générée qui pourrait être la cause de mon problème? Pourquoi est-ce là?

   Value1 Value2 Value3 ...  

Le champ caché est ce qui cause le problème. Mais c’est pour une bonne raison: lorsque toutes les valeurs sont désélectionnées, vous recevez toujours un paramètre subset_array. Dans les documents Rails (vous devrez peut-être faire défiler vers la droite pour voir tout cela):

  # 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_atsortingbutes(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 ssortingng, that works for ordinary forms. 

EDIT: Le dernier paragraphe suggère que vous ne devriez pas voir le vide dans le cas où quelque chose est sélectionné, mais je pense que c’est faux. La personne qui a fait cette validation sur Rails (voir https://github.com/rails/rails/commit/faba406fa15251cdc9588364d23c687a14ed6885 ) essaie de faire le même tour que Rails utilise pour les cases à cocher (comme mentionné ici: https://github.com / rails / rails / pull / 1552 ), mais je ne pense pas que cela puisse fonctionner pour une boîte de sélection multiple car les parameters envoyés forment un tableau dans ce cas et donc aucune valeur n’est ignorée.

Donc, mon sentiment est que c’est un bug.

En Rails 4:

Vous pourrez passer :include_hidden option :include_hidden . https://github.com/rails/rails/pull/5414/files

Comme solution rapide pour le moment: vous pouvez utiliser dès maintenant dans votre modèle:

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

Cela supprimera simplement toutes les valeurs vides au niveau du modèle.

Une autre solution rapide consiste à utiliser ce filtre de contrôleur:

 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 

Cette méthode peut être réutilisée sur les contrôleurs sans toucher à la couche modèle.

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

Je t’ai eu

La spécification HTML indique que les cases à cocher ou les sélections non vérifiées échouent et que les navigateurs Web ne les envoient pas. Malheureusement, cela introduit un piège: si un modèle de facture comporte un indicateur de paiement et que le formulaire qui modifie une facture payée est désactivé, l’utilisateur décoche sa case, aucun paramètre payé n’est envoyé. Donc, tout idiome d’affectation de masse comme

@ invoice.update (params [: facture]) ne mettrait pas à jour l’indicateur.

Pour éviter cela, l’assistant génère un champ caché auxiliaire avant la case à cocher very. Le champ masqué porte le même nom et ses atsortingbuts imitent une case non cochée.

De cette façon, le client envoie uniquement le champ masqué (représentant la case à cocher non cochée) ou les deux champs. Comme la spécification HTML indique que les paires clé / valeur doivent être envoyées dans le même ordre qu’elles apparaissent dans le formulaire et que l’extraction des parameters obtient la dernière occurrence de toute clé répétée dans la chaîne de requête, cela fonctionne pour les formulaires ordinaires.

Pour supprimer les valeurs vides:

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

Dans Rails 4+ set: include_hidden sur select_tag à false

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

Dans le contrôleur:

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

Je l’ai corrigé en utilisant les params[:review][:staff_ids].delete("") dans le contrôleur avant la mise à jour.

À mon avis:

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

Dans mon contrôleur:

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

Je le fais fonctionner en écrivant ceci dans la partie Javascript de la page:

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

Le mien ressemble plus au suivant:

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

Je ne sais pas si cela va me faire mal à la tête à l’avenir, mais maintenant ça marche bien.

Utilisez jQuery:

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

Option pour supprimer les options vides de la liste déroulante.