एक एम्बेडेड सरणी का उपयोग करके मेरा रेल बहु-चयन में पहला तत्व हमेशा रिक्त क्यों रहता है?


84

मैं रेल का उपयोग कर रहा हूँ 3.2.0.rc2 । मुझे एक मिला है Model, जिसमें मेरे पास एक स्टेटिक है Arrayजिसे मैं एक ऐसे फॉर्म के माध्यम से पेश कर रहा हूं, जिसमें उपयोगकर्ता एक सबसेट का चयन कर सकते हैं Arrayऔर अपने चयन को डेटाबेस में सहेज सकते हैं, जिसे एक कॉलम में संग्रहीत किया गया है Model। मैंने डेटाबेस कॉलम पर क्रमबद्ध उपयोग किया है जो स्टोर करता है Arrayऔर रेल सही ढंग से उपयोगकर्ताओं के चयन को यमल (और उस कॉलम को पढ़ते समय एक सरणी में वापस) में परिवर्तित कर रहा है। मैं चयन करने के लिए एक बहु-चयन फ़ॉर्म इनपुट का उपयोग कर रहा हूं।

मेरी समस्या यह है कि, जिस तरह से मेरे पास वर्तमान में है, वह सब कुछ काम करता है जैसा कि मैं अपेक्षा करता हूं कि उपयोगकर्ता के सबसेट एरे में हमेशा एक खाली पहला तत्व होता है जब इसे सर्वर पर भेजा जाता है।

यह कोई बड़ी बात नहीं है, और मैं इस तथ्य के बाद इसे काटने के लिए कोड लिख सकता हूं, लेकिन मुझे ऐसा लगता है कि मैं बस किसी प्रकार की वाक्यविन्यास त्रुटि कर रहा हूं क्योंकि यह मुझे ऐसा नहीं लगता कि डिफ़ॉल्ट रूप से रेल व्यवहार जानबूझकर होता है। बिना किसी कारण के इस रिक्त तत्व को जोड़ें। मुझे कुछ याद नहीं होगा या कुछ प्रकार की सेटिंग को अक्षम करना भूल गया। कृपया मुझे यह समझने में मदद करें कि मैं क्या याद कर रहा हूँ (या मुझे कुछ अच्छे दस्तावेज़ों की ओर इशारा करता हूँ जो इस बात का वर्णन करता है कि मैं इंटरब्यूटेस पर क्या पाया है, उससे कहीं अधिक गहराई के साथ)।

MySQL डाटाबेस टेबल 'मॉडल':

  • एक स्तंभ शामिल है जिसका नाम subset_arrayTEXT फ़ील्ड है

क्लास मॉडल में निम्नलिखित सेटिंग्स शामिल हैं:

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

संपादन के लिए मॉडल में निम्नलिखित इनपुट विकल्प शामिल हैं:

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

क्लाइंट से सर्वर पर PUT कुछ इस तरह दिखता है:

  • केवल मान 1 और मान 3 का चयन किया जाता है
  • "model" => { "subset_array" => ["", value1, value3] }

डेटाबेस अद्यतन इस तरह दिखता है:

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

जैसा कि आप देख सकते हैं, इस अतिरिक्त, रिक्त, सरणी में तत्व भेजा जा रहा है और डेटाबेस में सेट किया गया है। मैं उससे कैसे छुटकारा पाऊं? क्या कोई पैरामीटर है जो मुझे अपने f.selectकॉल से याद आ रहा है ?

बहुत धन्यवाद की सराहना की :)

EDIT : यह f.selectकथन से उत्पन्न HTML कोड है । ऐसा लगता है कि जैसे कोई गुप्त इनपुट उत्पन्न हो रहा है, जो मेरे मुद्दे का कारण हो सकता है? ऐसा क्यों है?

<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>

क्या आप HTML स्निपेट पोस्ट कर रहे हैं जो f.selectउत्पन्न कर रहा है? इसके अलावा, क्या यह व्यवहार बनाने पर भी होता है, या यह सिर्फ अपडेट पर है?
माइक ए।

उत्पादन HTML के संपादित जोड़ा मार्कअप से उत्पन्नf.select
robmclarty

@ माइक-दोनों के लिए एक समान व्यवहार की पुष्टि करें और अद्यतन करें
लूटमार्टार्टी

मुझे आश्चर्य है कि अगर मैं जिस ब्राउज़र का उपयोग कर रहा था वह समस्या का हिस्सा हो सकता है: यह कैसे व्याख्या करता है और छिपे हुए इनपुट टैग के अर्थ को उसी नाम के साथ चुनिंदा टैग के रूप में व्यक्त करता है। इसलिए मैंने क्रोम, सफारी, फ़ायरफ़ॉक्स और ओपेरा में अपने ऐप की कोशिश की, और प्रत्येक ने एक ही परिणाम का उत्पादन किया।
रोबक्क्लेर्टी

1
ध्यान दें, उपयोग करने वाले सभी समाधान include_hidden: falseएक गोच के साथ आते हैं। जब आप चयनित बॉक्स से सभी मान निकालते हैं, तो मुहावरेदार model.update(something_params)उस फ़ील्ड को शामिल नहीं करेगा। TL; DR आप क्षेत्र को खाली नहीं कर पाएंगे।
डेमन

जवाबों:


51

छिपा हुआ क्षेत्र वह है जो समस्या पैदा कर रहा है। लेकिन यह एक अच्छे कारण के लिए है: जब सभी मानों का चयन रद्द कर दिया जाता है, तब भी आपको एक सबसेट_अरे पैरामीटर प्राप्त होता है। रेल डॉक्स से (आपको यह सब देखने के लिए दाईं ओर स्क्रॉल करना पड़ सकता है):

  # 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.

संपादित करें: अंतिम पैराग्राफ बताता है कि जब आप कुछ चुने जाते हैं तो आपको मामले में खाली नहीं देखना चाहिए, लेकिन मुझे लगता है कि यह गलत है। जिस व्यक्ति ने रेल के लिए इसे प्रतिबद्ध किया है ( https://github.com/rails/rails/commit/faba406fa15251cdc9588364d2387614a14ed6885 देखें ) वही करने की कोशिश कर रहा है जो रेल चेकबॉक्स के लिए उपयोग करता है (जैसा कि यहां उल्लेख किया गया है: https://github.com / रेल / रेल / पुल / 1552 ), लेकिन मुझे नहीं लगता कि यह कई चुनिंदा बॉक्स के लिए काम कर सकता है क्योंकि पैरामीटर इस मामले में एक सरणी बनाते हैं और इसलिए कोई मूल्य अनदेखा नहीं किया जाता है।

तो मेरी भावना यह है कि यह एक बग है।


1
मैंने इस समस्या को प्रदर्शित करने के लिए एक उदाहरण ऐप बनाया है , जब मैं यह पता लगाने की कोशिश करता हूं कि इसे ठीक से कैसे संभालना है: P
robmclarty

1
मुझे लगता है कि बग आवश्यक रूप से रेल में नहीं है, लेकिन इस विशिष्ट तत्व कार्यक्षमता के लिए अस्पष्ट विनिर्देश और कार्यान्वयन में है। कैसे एक उपयोगकर्ता-एजेंट राज्य का एक परिवर्तन व्यक्त की चाहिए नव खाली प्रपत्र प्रोसेसर के लिए अगर खाली (या गैर चयनित) प्रपत्र तत्व माना जाता है नहीं होने के लिए सफल नियंत्रण है और इस तरह नहीं प्रपत्र सामग्री के साथ प्रस्तुत?
रोबक्लेर्टी

तो, अगर यह एक बग है, तो क्या यह रेल्स इश्यू ट्रैकर में प्रलेखित है?
बीएमएचएलएसी

69

रेल में 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

यह बस मॉडल स्तर पर सभी रिक्त मान हटा देगा।


धन्यवाद बोगदान। मुझे लगता है कि इस तरह की बात मैं इस मुद्दे पर काम करने के लिए अपने ऐप में लागू करूंगा। यह उपयोगकर्ता-एजेंटों के HTML कल्पना कार्यान्वयन या कुछ और के साथ मुद्दों पर काम करने की कोशिश करने की तुलना में बहुत आसान है।
रोबक्लेर्टी

अपनी चिंताओं को टीम के मुख्य सदस्यों तक पहुंचाएं। वे पैच की समीक्षा करने और उन्हें स्वीकार करने और परिणामी मुद्दों के लिए जिम्मेदारियां लेने के लिए अधिकृत हैं।
बोगदान गुसिएव

बोगदान, वैसे भी छिपे हुए क्षेत्र को बंद करने के लिए है, अगर कई सच है? 3.2 में अपग्रेड करने पर यह मेरे ऐप में काफी टूट जाता है। मैं वास्तव में इस तथ्य को पसंद नहीं करता कि मुझे अतिरिक्त खाली मूल्यों को जोड़ने वाले रेल जादू के कारण नियंत्रक में सामान को साफ करना होगा।
तायेलर

मेरे उत्तर को रेल 4 से जानकारी के साथ अद्यतन करें
बोगन गुसिएव

2
@ डोनटो को आपको सेट करना होगा_ शामिल करने के लिए गलत (शामिल: गलत: झूठे)
फ्लोरियन विडमैन

14

रेल 4+ सेट में: झूले में select_tag पर शामिल_हेड

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

यह अब तक का सबसे सरल उत्तर है! धन्यवाद!
विलियम हैम्पशायर

11

इस नियंत्रक फ़िल्टर का उपयोग करने के लिए एक और त्वरित सुधार है:

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

इस तरह से मॉडल परत को छूने के बिना नियंत्रकों में पुन: उपयोग किया जा सकता है।


धन्यवाद। अगर मैं इसे मॉडल में नहीं करना चाहता हूं तो मैं इसे अपने ट्रिक्स के बैग में शामिल कर रहा हूं;)
22

5

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

पकड़ लिया

HTML विनिर्देश का कहना है कि अनियंत्रित चेक बॉक्स या चयन सफल नहीं हैं, और इस प्रकार वेब ब्राउज़र उन्हें नहीं भेजते हैं। दुर्भाग्य से यह एक गोचर का परिचय देता है: यदि एक चालान मॉडल में एक भुगतान किया गया झंडा होता है, और एक भुगतान किए गए चालान को संपादित करने वाले रूप में उपयोगकर्ता अपने चेक बॉक्स को अनचेक करता है, तो कोई भुगतान किया गया पैरामीटर नहीं भेजा जाता है। तो, किसी भी मास-असाइनमेंट मुहावरे की तरह

@ input.update (params [: चालान]) ध्वज को अपडेट नहीं करेगा।

इसे रोकने के लिए सहायक बहुत ही चेक बॉक्स से पहले एक सहायक छिपा क्षेत्र उत्पन्न करता है। छिपे हुए फ़ील्ड का नाम समान है और इसकी विशेषताएँ एक अनियंत्रित चेक बॉक्स की नकल करती हैं।

इस तरह, क्लाइंट या तो केवल छिपा हुआ फ़ील्ड भेजता है (चेक बॉक्स का प्रतिनिधित्व अनियंत्रित होता है), या दोनों फ़ील्ड। चूंकि HTML विनिर्देश कहता है कि कुंजी / मूल्य जोड़े को उसी क्रम में भेजा जाना है जो वे फॉर्म में दिखाई देते हैं, और पैरामीटर निष्कर्षण को क्वेरी स्ट्रिंग में किसी भी दोहराया कुंजी की अंतिम घटना मिलती है, जो सामान्य रूपों के लिए काम करती है।

रिक्त मान निकालने के लिए:

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


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

0

मैं इसे पृष्ठ के जावास्क्रिप्ट भाग में लिखकर काम करता हूं:

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

मेरा निम्नलिखित की तरह लग रहा है:

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

यकीन नहीं होता कि इससे मुझे भविष्य में सिरदर्द होने वाला है लेकिन अब यह ठीक काम करता है।


-3

JQuery का उपयोग करें:

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

ड्रॉप डाउन से रिक्त विकल्प हटाने का विकल्प।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.