Reputation: 2748
I am trying to create a web app that could be used for submitting answers to quizes. And I am having troubles creating the view files.
The submission form should look like this (sorry, SO does not allow me to insert images in the body of the question).
It is a case of nested model forms discussed by Ryan Bates in Railscasts, but there is an important difference. In Ryan Bates' case there is a simple chain of associations: a Survey model has many Questions, and each Question has many Answers.
What I am planning, though, is a bit more complex. In my case, a Quiz has many Questions, and a Question has many Answers, but what a user is presented with is a model called Submission. A Submission is associated with the User model and the Answer model, and it also has some additional information. Schematically, my associations look like this:
So I need to create a form that will combine a model (Submission) with many unassociated models (Questions) and many associated models (Answers). All I could think of for my new/edit view file is this:
Controller:
# GET /tests/:test_id/submissions/new
def new
@quiz = Quiz.find(params[:quiz_id])
# the next four lines of code are to select a subset of questions
variant = choose_variant(@quiz)
@submission = Submission.new
@submission.variant = variant
@questions = Question.where (variant: variant)
@questions.each {|question| quiestion.answers.build}
end
View:
= form_for [@quiz, @submission] do |f|
= f.fields_for :answers do |builder|
= @questions.each do |question|
%p
= @question.text
= builder.label :answer_text, "Your answer"
= builder.text_area :answer_text
But it doesn't look right: there is no association between the @submission, the @question and the answers. Could you please suggest how to solve this problem if there is no direct association between the Submission and the Question model?
UPDATE:
I can now create a form in the view:
= form_for [@quiz, @submission] do |f|
- @questions.each do |question|
%p
= question.text
= f.fields_for :answer, question.answers.first do |builder|
= builder.label :text, "Answer"
= builder.text_area :text
The trouble is, on submit the last answer overwrites all the privious answers, and in the params I get only:
"submission"=>{"answer"=>{"text"=>"Answer to the last question"}}
UPDATE 2:
To Marcelo Risoli (sorry, I haven't got the hang of StackOverflow behavior, and it doesn't allow me to write another comment). I apologize, I did not quite understand your suggestion at first. Your line @questions.each { |q| @submission.answers.build question_id: q.id }
is pure genius: it associates answers
with the submission
in the controller instead of in the view, as I initially tried to do. Will try do go through with your suggestion and will write back. But it seems like this line will solve all my problems :-)
Upvotes: 0
Views: 617
Reputation: 802
I did something very similar, I can give you some suggestions:
First, I'd advise you use cocoon, nested form is not being updated anymore, and I found cocoon to be much easier to deal with.
Second, the submission does not need association with the question, if necessary you can access a question with a given submission with the a has_many: :through association.
When you use fields_for :answers in a form_for submission means the newly created submission_id will be input into the answers, now all you need is to input the question_id, you can do that through a hidden input, just do the following in your controller:
@questions.each { |q| @submission.answers.build question_id: q.id }
then add = builder.input :question_id, as: :hidden
to your form
Upvotes: 0
Reputation: 96594
Use appropriate join tables. Suggest you use an 'answer' table for the actual answer that a user makes. Use question_options
and option_groups
for the possible answers for a question.
Suggest you consider basing it on https://stackoverflow.com/a/5858666/631619
Just substitute 'survey' for 'quiz'
Upvotes: 1