Câu hỏi Tại sao phần tử đầu tiên luôn trống trong đa Rails của tôi, sử dụng một mảng được nhúng?


Tôi đang sử dụng Rails 3.2.0.rc2. tôi có một Model, trong đó tôi có tĩnh Array mà tôi cung cấp thông qua biểu mẫu để người dùng có thể chọn một tập hợp con Array và lưu lựa chọn của họ vào cơ sở dữ liệu, được lưu trữ trong một cột duy nhất trong Model. Tôi đã sử dụng serialize trên cột cơ sở dữ liệu lưu trữ Array và Rails đang chuyển đổi chính xác các lựa chọn của người dùng thành Yaml (và quay lại mảng khi đọc cột đó). Tôi đang sử dụng đầu vào biểu mẫu nhiều lựa chọn để thực hiện lựa chọn.

Vấn đề của tôi là, cách tôi hiện đang có nó, mọi thứ hoạt động như tôi mong đợi ngoại trừ mảng con của người dùng luôn luôn có một phần tử trống đầu tiên khi nó được gửi đến máy chủ.

Đây không phải là một vấn đề lớn, và tôi có thể viết mã để cắt nó ra sau khi thực tế, nhưng tôi cảm thấy như tôi đang tạo ra một số lỗi cú pháp vì dường như hành vi Rails mặc định sẽ cố ý thêm phần tử trống này mà không có lý do nào. Tôi đã phải bỏ lỡ một cái gì đó hoặc quên vô hiệu hóa một số loại thiết lập. Xin vui lòng giúp tôi hiểu những gì tôi đang thiếu (hoặc chỉ cho tôi một số tài liệu tốt mô tả điều này với chiều sâu hơn những gì tôi đã có thể tìm thấy trên intertubes).

Bảng cơ sở dữ liệu MySQL 'mô hình':

  • bao gồm một cột có tên subset_array đó là trường TEXT

Mô hình lớp bao gồm các cài đặt sau:

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

Biểu mẫu để chỉnh sửa Mô hình bao gồm tùy chọn nhập sau:

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

PUT cho máy chủ từ máy khách trông giống như sau:

  • giả định chỉ có giá trị 1 và giá trị 3 được chọn
  • "model" => { "subset_array" => ["", value1, value3] }

Cập nhật cơ sở dữ liệu trông giống như sau:

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

Như bạn có thể thấy, có phần tử thừa, trống này trong mảng đang được gửi và được đặt trong cơ sở dữ liệu. Làm thế nào để tôi thoát khỏi điều đó? Có một tham số tôi đang thiếu từ f.select gọi điện?

Cảm ơn nhiều đánh giá cao :)

CHỈNH SỬA: Đây là mã HTML được tạo từ f.select tuyên bố. Dường như có một đầu vào ẩn được tạo ra có thể là nguyên nhân gây ra vấn đề của tôi? Tại sao lại có?

<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


gốc


Bạn có thể đăng đoạn mã HTML mà f.select đang tạo ra? Ngoài ra, hành vi này có xảy ra ngay cả khi tạo, hay chỉ là cập nhật? - Mike A.
Đã thêm EDIT của đánh dấu HTML đầu ra được tạo từ f.select - robmclarty
@ mike-a Hành vi tương tự đã được xác nhận cho cả việc tạo và cập nhật - robmclarty
Tôi tự hỏi liệu trình duyệt tôi đang sử dụng có thể là một phần của vấn đề hay không: cách nó diễn giải và thể hiện ý nghĩa của thẻ đầu vào bị ẩn có cùng tên với thẻ chọn. Vì vậy, tôi đã thử ứng dụng của mình trong Chrome, Safari, Firefox và Opera và mỗi ứng dụng đều có cùng kết quả. - robmclarty
Lưu ý, tất cả các giải pháp sử dụng include_hidden: false đi kèm với một gotcha. Khi bạn xóa tất cả các giá trị khỏi hộp chọn, thành ngữ model.update(something_params) sẽ không bao gồm trường đó. TL, DR bạn sẽ không thể làm cho trường trống. - Damon Aw


Các câu trả lời:


Trường ẩn là điều gây ra sự cố. Nhưng nó có lý do chính đáng: khi tất cả các giá trị được bỏ chọn, bạn vẫn nhận được một tham số subset_array. Từ tài liệu Rails (bạn có thể phải cuộn sang bên phải để xem tất cả điều này):

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

CHỈNH SỬA: Đoạn cuối cho thấy rằng bạn không nên nhìn thấy cái trống trong trường hợp khi một cái gì đó được chọn, nhưng tôi nghĩ nó sai. Người đã thực hiện cam kết này với Rails (xem https://github.com/rails/rails/commit/faba406fa15251cdc9588364d23c687a14ed6885) đang cố gắng thực hiện cùng một mẹo mà Rails sử dụng cho các hộp kiểm (như đã đề cập ở đây: https://github.com/rails/rails/pull/1552), nhưng tôi không nghĩ rằng nó có thể làm việc cho một hộp chọn nhiều bởi vì các thông số được gửi qua tạo thành một mảng trong trường hợp này và do đó không có giá trị được bỏ qua.

Vì vậy, cảm giác của tôi là đây là một lỗi.


51
2018-01-19 20:50



Tôi đã tạo một ứng dụng ví dụ để chứng minh vấn đề trong khi tôi cố gắng tìm ra cách xử lý nó đúng cách: P - robmclarty
Tôi cảm thấy như lỗi không nhất thiết trong Rails, nhưng trong một đặc tả và triển khai không rõ ràng cho chức năng yếu tố cụ thể này. Tác nhân người dùng nên thể hiện sự thay đổi trạng thái mới trống cho bộ xử lý biểu mẫu nếu các phần tử biểu mẫu trống (hoặc không được chọn) được xem xét không phải được điều khiển thành công và như vậy không phải đã gửi với nội dung biểu mẫu? - robmclarty
Vì vậy, nếu đây là một lỗi, nó có được ghi lại trong bộ theo dõi vấn đề Rails không? - bmihelac


Trong Rails 4:

Bạn sẽ có thể vượt qua :include_hidden Tùy chọn. https://github.com/rails/rails/pull/5414/files

Để khắc phục nhanh ngay bây giờ: bạn có thể sử dụng ngay bây giờ trong mô hình của mình:

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

Điều này sẽ chỉ xóa tất cả các giá trị trống ở cấp mô hình.


63
2018-01-20 09:27



Cảm ơn Bogdan. Tôi nghĩ rằng đây là loại điều tôi sẽ thực hiện trong ứng dụng của mình để giải quyết vấn đề. Điều này dễ làm hơn rất nhiều so với việc cố gắng giải quyết các vấn đề với việc triển khai thông số HTML của người dùng của tác nhân người dùng hoặc thứ gì đó. - robmclarty
Mang lại những lo ngại của bạn để hướng dẫn các thành viên trong nhóm cốt lõi. Họ được ủy quyền để xem xét và chấp nhận các bản vá lỗi và chịu trách nhiệm về các vấn đề hậu quả. - Bogdan Gusiev
Bogdan, có anyway để tắt lĩnh vực ẩn, nếu nhiều là sự thật? Điều này phá vỡ khá nhiều thứ trong ứng dụng của tôi khi nâng cấp lên 3.2. Tôi thực sự không thích thực tế là tôi phải làm sạch công cụ trong bộ điều khiển vì phép thuật Rails bổ sung thêm các giá trị rỗng. - taelor
@BogdanGusiev include_hidden dường như không hoạt động trong Rails 4 - Donato
@ Donato bạn phải đặt include_hidden thành false (include_hidden: false) - Florian Widtmann


Một sửa chữa nhanh khác là sử dụng bộ lọc điều khiển này:

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

Bằng cách này có thể được tái sử dụng trên các bộ điều khiển mà không cần chạm vào lớp mô hình.


10
2018-01-31 19:21



cảm ơn. Tôi đang thêm điều này vào túi của tôi về thủ thuật trong trường hợp tôi không muốn làm điều đó trong mô hình;) - robmclarty


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

Gotcha

Đặc điểm kỹ thuật HTML cho biết các hộp kiểm được chọn hoặc các lựa chọn không thành công,   và do đó các trình duyệt web không gửi chúng. Thật không may, phần giới thiệu này   một hình ảnh xác thực: nếu một mô hình Hóa đơn có một cờ có trả tiền và trong biểu mẫu   chỉnh sửa hóa đơn trả tiền mà người dùng bỏ chọn hộp kiểm của nó, không trả tiền   tham số được gửi. Vì vậy, bất kỳ thành ngữ giao hàng đại chúng như

@ invoice.update (params [: invoice]) sẽ không cập nhật cờ.

Để ngăn chặn điều này, trình trợ giúp tạo ra một trường ẩn phụ trợ trước   hộp kiểm rất. Trường ẩn có cùng tên và   các thuộc tính bắt chước một hộp kiểm được bỏ chọn.


5
2018-04-03 05:25





Trong bộ điều khiển:

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

3
2018-05-18 16:34





Trong tập hợp Rails 4+: include_hidden trên select_tag thành 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





Tôi đã sửa nó bằng cách sử dụng params[:review][:staff_ids].delete("") trong bộ điều khiển trước khi cập nhật.

Theo quan điểm của tôi:

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

Trong bộ điều khiển của tôi:

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





Tôi làm cho nó hoạt động bằng cách viết điều này trong phần Javascript của trang:

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

Mỏ trông giống như sau:

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

Không chắc chắn nếu điều này sẽ làm cho tôi đau đầu trong tương lai nhưng bây giờ nó hoạt động tốt.


0
2018-02-11 20:35





Sử dụng jQuery:

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

Tùy chọn để xóa các tùy chọn trống từ menu thả xuống.


-2
2018-04-04 13:36