I'm stuck with this simple selection task. I have this models:
# id :integer(4) not null, primary key
# category :string(255)
# content :text
class Question < ActiveRecord::Base
has_many :choices, :dependent => :destroy
accepts_nested_attributes_for :choices
end
# id :integer(4) not null, primary key
# content :text
# correct :boolean(1)
# question_id :integer(4)
class Choice < ActiveRecord::Base
belongs_to :question
end
When I create a new question, I want to specify in a nested form not only the content
of the Question
, but even the content
of 3 Answer
objects, and select with a radio button which one is the correct
answer. In the new
action of the controller, I have this:
def new
@title = "New Question"
@question = Question.new
3.times { @question.choices.build }
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @question }
end
end
This is the form code:
<%= simple_form_for @question do |question_form| %>
<%= question_form.error_notification %>
<div class="inputs">
<%= question_form.input :content, :label => 'Question' %>
<%= question_form.input :category, :collection => get_categories, :include_blank => false %>
<% @question.choices.each do |choice| %>
<%= question_form.fields_for :choices, choice do |choice_fields| %>
<%= choice_fields.input :content, :label => 'Choice' %>
<%= choice_fields.radio_button :correct, true %>
<%= choice_fields.label :correct, 'Correct Answer' %>
<% end %>
<% end %>
</div>
<div class="actions">
<%= question_form.button :submit %>
</div>
<% end %>
The problem is that this code produce three radio buttons with different names: you can select more than one correct answer, and this is not the correct behaviour. The names of the three radio buttons are question[choices_attributes][0][correct]
, question[choices_attributes][1][correct]
and question[choices_attributes][2][correct]
.
The question is: how can I create three radio buttons with the same name, in order to select one and only one correct answer? How can I create a correct params
array, in order to save them in the create
action in this way:
def create
@question = Question.new(params[:question])
# render or redirect stuff....
end
Thank you very much!
You can use radio_button_tag
and pass it your own name attribute.
Being that you are still in the choice_fields
scope, you have access to a few methods that can expose the object you are working on, which will help you name your radio_button_tag
properly.
The following code will give your radio button the proper name to be accepted as a nested attribute:
<%= radio_button_tag "question[choices_attributes][#{choice_fields.index}][correct]", true, choice_fields.object.correct %>
choice_fields.index
gives you access to the proper index of the resource being created, so the first coice will have the name question[choices_attributes][0][correct]
, the second one question[choices_attributes][1][correct]
, etc.
choice_fields.object.correct
gives you access to the current value so the correct radio button will be filled in for edit forms.
Update:
The solution above is actually wrong, it gives each radio button a different name
attribute so they don't end up working together (you can select multiple radio buttons at once).
The soltion I ended up going with was allong the following lines:
<%= radio_button_tag "question[choices_attributes][correct_choice]", choice_fields.index, choice_fields.object.correct %>
This gives each radio button the same name as the others, and a value equal to the index of the correct choice. The params hash ends up looking like this:
question: {choices_attributes: {
"0": {//choice 0},
"1": {//choice 1},
etc...
},
correct_choice: //index of correct answer
}
I then updated my controller to manually update the correct choice as follows:
def create
# Find the index of the correct choice in the params hash
correct_index = params[:question][:correct_choice]
# mark the question at the correct index as correct
params[:question][:choiceses_attributes][correct_index][:correct] = true
# Use the updated params hash to create a new Question/update an existing Question
@question = Question.new(params[:question])
# render or redirect stuff....
end
You can pass in the name option to the radio_button method:
<%= choice_fields.radio_button :correct, true, :name => "choices_attributes" %>
(From the rails docs, http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html : radio_button(object_name, method, tag_value, options = {}) )
Hope this helps.
This is a non-answer, but I'd recommend you try out Formtastic. It makes dealing with nested models like this STUPID EASY: https://github.com/justinfrench/formtastic
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With