Pertanyaan Mengapa elemen pertama selalu kosong di multisel Rails saya, menggunakan larik yang disematkan?


saya menggunakan Rails 3.2.0.rc2. Saya punya Model, di mana saya memiliki statis Array yang saya tawarkan melalui suatu bentuk sehingga pengguna dapat memilih bagian dari Array dan menyimpan pilihan mereka ke database, disimpan dalam satu kolom di Model. Saya telah menggunakan cerita bersambung pada kolom database yang menyimpan Array dan Rails mengubah pilihan pengguna dengan benar menjadi Yaml (dan kembali ke array saat membaca kolom itu). Saya menggunakan input bentuk multi-pilih untuk membuat pilihan.

Masalah saya adalah bahwa, cara saya saat ini memilikinya, semuanya bekerja seperti yang saya harapkan kecuali bahwa array subset pengguna selalu memiliki elemen kosong pertama ketika itu dikirim ke server.

Ini bukan masalah besar, dan saya bisa menulis kode untuk memotong itu setelah fakta, tapi saya merasa seperti saya hanya membuat semacam kesalahan sintaksis karena tampaknya saya tidak bahwa perilaku Rails standar akan sengaja tambahkan elemen kosong ini tanpa alasan. Saya pasti melewatkan sesuatu atau lupa menonaktifkan beberapa pengaturan. Tolong bantu saya memahami apa yang saya rindukan (atau tunjukkan saya pada beberapa dokumentasi bagus yang menggambarkan ini dengan lebih mendalam daripada apa yang dapat saya temukan di intertubes).

Tabel Basis Data MySQL 'model':

  • termasuk kolom bernama subset_array yang merupakan bidang TEXT

Model Kelas mencakup pengaturan berikut:

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

Formulir untuk mengedit Model menyertakan opsi input berikut:

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

PUT ke server dari klien terlihat seperti ini:

  • dengan asumsi hanya nilai1 dan nilai3 yang dipilih
  • "model" => { "subset_array" => ["", value1, value3] }

Pembaruan basis data terlihat seperti ini:

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

Seperti yang Anda lihat, ada ekstra, kosong, elemen dalam array yang dikirim dan diatur dalam database. Bagaimana cara menyingkirkannya? Apakah ada parameter yang saya lewatkan dari saya f.select panggilan?

Terima kasih banyak terima kasih :)

EDIT: Ini adalah kode HTML yang dihasilkan dari f.select pernyataan. Sepertinya ada masukan tersembunyi yang dihasilkan yang mungkin menjadi penyebab masalah saya? Kenapa disana?

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

76
2018-01-19 16:02


asal


Jawaban:


Bidang tersembunyi inilah yang menyebabkan masalah. Tapi itu ada untuk alasan yang bagus: ketika semua nilai tidak terpilih, Anda masih menerima parameter subset_array. Dari dokumen Rails (Anda mungkin harus menggulir ke kanan untuk melihat semua ini):

  # 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: Paragraf terakhir menunjukkan bahwa Anda seharusnya tidak melihat yang kosong dalam kasus ketika ada sesuatu yang dipilih, tapi saya pikir itu salah. Orang yang membuat ini berkomitmen untuk Rails (lihat https://github.com/rails/rails/commit/faba406fa15251cdc9588364d23c687a14ed6885) mencoba melakukan trik yang sama yang digunakan Rails untuk kotak centang (seperti yang disebutkan di sini: https://github.com/rails/rails/pull/1552), tapi saya tidak berpikir itu bisa bekerja untuk kotak pilihan ganda karena parameter yang dikirim melalui bentuk array dalam kasus ini dan jadi tidak ada nilai yang diabaikan.

Jadi perasaan saya adalah ini bug.


51
2018-01-19 20:50



Di Rails 4:

Anda akan bisa lulus :include_hidden pilihan. https://github.com/rails/rails/pull/5414/files

Sebagai perbaikan cepat untuk saat ini: Anda dapat menggunakan sekarang dalam model Anda:

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

Ini hanya akan menghapus semua nilai kosong pada level model.


63
2018-01-20 09:27



Perbaikan cepat lainnya adalah menggunakan filter pengontrol ini:

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

Cara ini dapat digunakan kembali di seluruh pengendali tanpa menyentuh lapisan model.


10
2018-01-31 19:21



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

Gotcha

Spesifikasi HTML mengatakan kotak centang yang tidak dicentang atau yang dipilih tidak berhasil,   dan dengan demikian browser web tidak mengirimnya. Sayangnya ini mengenalkan   gotcha: jika model Faktur memiliki bendera berbayar, dan dalam bentuk itu   mengedit faktur berbayar, pengguna tidak mencentang kotak centangnya, tidak membayar   parameter dikirim. Jadi, semua idiom penugasan seperti

@ invoice.update (params [: faktur]) tidak akan memperbarui bendera.

Untuk mencegah hal ini, helper akan menghasilkan bidang tersembunyi tambahan   sangat kotak centang. Bidang tersembunyi memiliki nama dan namanya sama   atribut meniru kotak centang yang tidak dicentang.


5
2018-04-03 05:25



Di pengontrol:

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

3
2018-05-18 16:34



Di Rails 4+ set: include_hidden pada select_tag ke false

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

3
2018-05-01 15:07



Saya memperbaikinya dengan menggunakan params[:review][:staff_ids].delete("") di controller sebelum pembaruan.

Dalam pandangan saya:

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

Di pengontrol saya:

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

0
2017-10-14 17:30



Saya membuatnya bekerja dengan menulis ini di bagian Javascript halaman:

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

Milik saya terlihat lebih seperti berikut:

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

Tidak yakin apakah ini akan membuat saya sakit kepala di masa depan tetapi sekarang berfungsi dengan baik.


0
2018-02-11 20:35



Gunakan jQuery:

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

Opsi untuk menghapus opsi kosong dari drop down.


-2
2018-04-04 13:36