I'm trying to create an HTML multiple select using collection_select
, to be able to update an entity (a Student
) which has a collection of another entity (a SubscriptionList
) as a nested attribute. This is backed up by a HABTM ActiveRecord's relation.
I have created the following form for the Student via scaffolding:
<div class="field">
<%= f.label :first_name %><br>
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %><br>
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :file_number %><br>
<%= f.text_field :file_number %>
</div>
<div class="field">
<%= f.label :subscription_list %><br>
<%= f.collection_select(:subscription_lists, SubscriptionList.all, :id, :name, {}, {:multiple => true}) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
and it draws the multiple select properly.
However, if I fill the form and try to PUT the entity, I'm getting this as the params:
{"utf8"=>"✓", "_method"=>"patch", "authenticity_token"=>"vXYMRYI1UtX7WJRZM0OPIhHQSSEyNOPyUxkUvScdu45PTL7qVhvlJfQYNvaKG5rw+mvHAAAbf6ViTQ6tE4lV1Q==", "student"=>{"first_name"=>" Mariana", "last_name"=>"González", "file_number"=>"12345678", "subscription_lists"=>["", "3"]}, "commit"=>"Update Student", "controller"=>"students", "action"=>"update", "id"=>"14"}
So, my Student is
"first_name"=>" Mariana", "last_name"=>"González", "file_number"=>"12345678", "subscription_lists"=>["", "3"]}
I find it very strange to be receiving ["", "3"]
as the values. Why I'm receiving this first ""
value?
I'm also posting here my Controller (actions other that update
have been deleted for brevity)
class StudentsController < ApplicationController
before_action :set_student, only: [:show, :edit, :update, :destroy, :enrollments]
# PATCH/PUT /students/1
# PATCH/PUT /students/1.json
def update
puts "\n\n\n\n\n\n\n\n\nThese are the params: #{params.inspect}"
puts "\n\n\n\n\nThis is student_params object: #{student_params.inspect}\n\n\nand its class #{student_params.class}"
#puts "\n\n\n\n\n\n\n\n\nWill look for SL with ID: #{params[:subscription_lists_id]}"
all_ids = student_params.subscription_lists.collect {|sl| sl.id }
@student.subscription_lists = SubscriptionList.find(all_ids)
#@student.subscription_lists = SubscriptionList.where(id: all_ids)
respond_to do |format|
if @student.update(student_params)
format.html { redirect_to @student, notice: 'Student was successfully updated.' }
format.json { render :show, status: :ok, location: @student }
else
format.html { render :edit }
format.json { render json: @student.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_student
@student = Student.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def student_params
#params[:student]
#params.require(:foo).permit(:bar, {:baz => [:x, :y]})
#params.require(:student).permit(:first_name, :last_name, :file_number, :subscription_lists)
params.require(:student).permit! # No strong parameters...
end
end
In fact, I'd rather receive a Student
with a nested collection of SubscriptionList
instead of just receving an array of ids, but I'm not sure if this is even possible.
Any help would be really appreciated.
Best regards
About your question has been answered in collection select always adding blank value.
You will get [""]
when you did not select anything or you select your options select as default. To avoid this you have to add hidden_field
before the collection select.
<div class="field">
<%= f.label :subscription_lists %><br>
<%= f.hidden_field :subscription_lists %>
<%= f.collection_select(:subscription_lists, SubscriptionList.all, :id, :name, {}, {:multiple => true}) %>
</div>
The hidden_field
helps you when it's nothing selected. How about when you choose it? Please try this.
def update
if student_params["subscription_lists"].any?
student_params["subscription_lists"].reject!(&:empty?)
end
respond_to do |format|
if @student.update(student_params)
format.html { redirect_to @student, notice: 'Student was successfully updated.' }
format.json { render :show, status: :ok, location: @student }
else
format.html { render :edit }
format.json { render json: @student.errors, status: :unprocessable_entity }
end
end
end
I hope this help you.