Rails: выбор переключателя для вложенных объектов
Я застрял в этой простой задаче выбора. У меня есть эти модели:
# 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
Когда я создаю новый вопрос, я хочу указать в вложенной форме не только content
объекта Question
, но даже content
из 3 Answer
объектов и выбрать с помощью переключателя, который один - ответ correct
. В действии контроллера new
у меня есть следующее:
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
Это код формы:
<%= 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 %>
Проблема заключается в том, что этот код создает три переключателя с разными именами: вы можете выбрать более одного правильного ответа, и это неправильное поведение. Названия трех переключателей: question[choices_attributes][0][correct]
, question[choices_attributes][1][correct]
и question[choices_attributes][2][correct]
.
Возникает вопрос: как я могу создать три переключателя с тем же именем, чтобы выбрать один и только один правильный ответ? Как создать правильный массив params
, чтобы сохранить их в действии create
таким образом:
def create
@question = Question.new(params[:question])
# render or redirect stuff....
end
Большое спасибо!
Ответы
Ответ 1
Вы можете использовать radio_button_tag
и передать ему свой собственный атрибут имени.
Поскольку вы все еще находитесь в области choice_fields
, у вас есть доступ к нескольким методам, которые могут подвергать объект, над которым вы работаете, что поможет вам правильно назвать ваш radio_button_tag
.
Следующий код даст вашему переключателю правильное имя, которое будет принято как вложенный атрибут:
<%= radio_button_tag "question[choices_attributes][#{choice_fields.index}][correct]", true, choice_fields.object.correct %>
choice_fields.index
дает вам доступ к соответствующему индексу создаваемого ресурса, поэтому первый койч будет иметь имя question[choices_attributes][0][correct]
, второе question[choices_attributes][1][correct]
и т.д.
choice_fields.object.correct
дает вам доступ к текущему значению, поэтому для редактирования форм будет заполнен правильный переключатель.
Update:
Вышеприведенное решение на самом деле неверно, оно дает каждому переключателю другой атрибут name
, поэтому они не работают вместе (вы можете сразу выбрать несколько переключателей).
В результате, в котором я закончил, были следующие строки:
<%= radio_button_tag "question[choices_attributes][correct_choice]", choice_fields.index, choice_fields.object.correct %>
Это дает каждому переключателю то же имя, что и остальные, и значение, равное индексу правильного выбора. Хеш params выглядит следующим образом:
question: {choices_attributes: {
"0": {//choice 0},
"1": {//choice 1},
etc...
},
correct_choice: //index of correct answer
}
Затем я обновил свой контроллер, чтобы вручную обновить правильный выбор следующим образом:
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
Ответ 2
Вы можете передать имя опции методу radio_button:
<%= choice_fields.radio_button :correct, true, :name => "choices_attributes" %>
(Из рельсов docs, http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html: radio_button (object_name, method, tag_value, options = {}))
Надеюсь, это поможет.
Ответ 3
Это не ответ, но я бы порекомендовал вам попробовать Formtastic. Это делает работу с вложенными моделями, такими как STUPID EASY: https://github.com/justinfrench/formtastic
Ответ 4
Это определенно работает на Rails 4. Не проверял другие версии:
Ваши метки и поля должны выглядеть так:
<%= choice_fields.radio_button :correct, true %>
<%= choice_fields.label :correct, value: true, do %>
'True'
<% end %>
<%= choice_fields.radio_button :correct, false %>
<%= choice_fields.radio_button :correct, value: false, do %>
'False'
<% end %>
Чтобы метка вызывала переключатель на клике, вы должны иметь value: whatever_your_value_is
в <%= choice_fields.label ... %>