임베디드 배열을 사용하여 Rails 다중 선택에서 첫 번째 요소가 항상 비어있는 이유는 무엇입니까?
Rails 3.2.0.rc2를 사용 하고 있습니다. 나는를 가지고 Model
있는 나는 정적이, Array
나는 사용자의 하위 집합을 선택할 수 있도록 형태를 통해 제공하고있어 Array
및 단일 열에 저장된 데이터베이스, 자신의 선택 사항을 저장을 Model
. 를 저장하는 데이터베이스 열에서 직렬화를 사용 Array
했으며 Rails는 사용자의 선택을 Yaml로 올바르게 변환하고 해당 열을 읽을 때 배열로 다시 변환합니다. 다중 선택 양식 입력을 사용하여 선택하고 있습니다.
내 문제는 내가 현재 가지고있는 방식으로, 사용자의 하위 집합 배열이 서버로 전송 될 때 항상 빈 첫 번째 요소가 있다는 점을 제외하고는 모든 것이 예상대로 작동한다는 것입니다.
이것은 큰 문제가 아니며, 사실 후에 그것을 잘라내는 코드를 작성할 수 있지만, 기본 Rails 동작이 의도적으로 작동하지 않는 것 같아서 일종의 구문 오류를 만드는 것처럼 느껴집니다. 어떤 이유없이이 빈 요소를 추가합니다. 나는 무언가를 놓쳤거나 어떤 종류의 설정을 비활성화하는 것을 잊었을 것입니다. 내가 놓친 것이 무엇인지 이해하도록 도와주세요 (또는 intertubes에서 찾을 수 있었던 것보다 더 깊이 이것을 설명하는 좋은 문서를 알려주세요).
MySQL 데이터베이스 테이블 '모델':
subset_array
TEXT 필드 인 이름 이 지정된 열을 포함 합니다.
클래스 모델에는 다음 설정이 포함됩니다.
serialize :subset_array
ALL_POSSIBLE_VALUES = [value1, value2, value3, ...]
모델 편집을위한 양식에는 다음 입력 옵션이 포함됩니다.
f.select :subset_array, Model::ALL_POSSIBLE_VALUES, {}, :multiple => true, :selected => @model.subset_array
클라이언트에서 서버로의 PUT는 다음과 같습니다.
- value1 및 value3 만 선택되었다고 가정합니다.
"model" => { "subset_array" => ["", value1, value3] }
데이터베이스 업데이트는 다음과 같습니다.
UPDATE 'models' SET 'subset_array' = '--- \n- \"\"\n- value1\n- value3\n'
보시다시피, 데이터베이스에 전송되고 설정되는 배열에이 여분의 빈 요소가 있습니다. 어떻게 제거합니까? 내 f.select
호출 에서 누락 된 매개 변수가 있습니까?
대단히 감사합니다 :)
편집 : 이것은 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>
숨겨진 필드가 문제의 원인입니다. 하지만 그럴만 한 이유가 있습니다. 모든 값이 선택 취소 되어도 하위 집합 _ 배열 매개 변수가 계속 수신됩니다. Rails 문서에서 (이 모든 것을 보려면 오른쪽으로 스크롤해야 할 수도 있습니다) :
# 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.
편집 : 마지막 단락은 무언가가 선택되었을 때 빈 것을 보지 말아야한다고 제안하지만 잘못되었다고 생각합니다. Rails에이 커밋을 한 사람 ( https://github.com/rails/rails/commit/faba406fa15251cdc9588364d23c687a14ed6885 참조 )은 Rails가 체크 박스에 사용하는 것과 동일한 트릭을 시도하고 있습니다 (여기에 언급 된대로 : https://github.com). / rails / rails / pull / 1552 ),하지만이 경우 전송 된 매개 변수가 배열을 형성하므로 값이 무시되지 않기 때문에 다중 선택 상자에서 작동하지 않는다고 생각합니다.
제 느낌은 이것이 버그라는 것입니다.
Rails 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
This will just delete all blank values at model level.
Another quick fix is to use this controller filter:
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
This way can be reused across controllers without touching the model layer.
In Rails 4+ set :include_hidden on select_tag to false
<%= form.grouped_collection_select :employee_id, Company.all, :employees, :name, :id, :name, { include_hidden: false }, { size: 6, multiple: true } %>
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-check_box
Gotcha
The HTML specification says unchecked check boxes or selects are not successful, and thus web browsers do not send them. Unfortunately this introduces a gotcha: if an Invoice model has a paid flag, and in the form that edits a paid invoice the user unchecks its check box, no paid parameter is sent. So, any mass-assignment idiom like
@invoice.update(params[:invoice]) wouldn't update the flag.
To prevent this the helper generates an auxiliary hidden field before the very check box. The hidden field has the same name and its attributes mimic an unchecked check box.
This way, the client either sends only the hidden field (representing the check box is unchecked), 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.
To remove blank values:
def myfield=(value)
value.reject!(&:blank?)
write_attribute(:myfield, value)
end
In the controller:
arr = arr.delete_if { |x| x.empty? }
I fixed it using the params[:review][:staff_ids].delete("")
in the controller before the update.
In my view:
= form_for @review do |f|
= f.collection_select :staff_ids, @business.staff, :id, :full_name, {}, {multiple:true}
= f.submit 'Submit Review'
In my controller:
class ReviewsController < ApplicationController
def create
....
params[:review][:staff_ids].delete("")
@review.update_attribute(:staff_ids, params[:review][:staff_ids].join(","))
....
end
end
I make it work by writing this in the Javascript part of the page:
$("#model_subset_array").val( <%= @model.subset_array %> );
Mine looks more like following:
$("#modela_modelb_ids").val( <%= @modela.modelb_ids %> );
Not sure if this is going to get me headache in the future but now it works fine.
Use jQuery:
$('select option:empty').remove();
Option to remove blank options from drop down.
'Development Tip' 카테고리의 다른 글
gdb에 코어 파일 저장 (0) | 2020.10.07 |
---|---|
HttpRequest.execute () 사용 예외 : SingleClientConnManager의 잘못된 사용 : 연결이 여전히 할당 됨 (0) | 2020.10.07 |
FORM 내에서 DIV를 사용하는 것이 맞습니까? (0) | 2020.10.07 |
인수로 확장되는 PROTOTYPE 매크로의 요점은 무엇입니까? (0) | 2020.10.07 |
탭 인덱스에서 다음 요소에 초점 맞추기 (0) | 2020.10.07 |