fields_for not nesting attributes - ruby-on-rails

I have this form:
<%= form_for(:quiz_responses, url: quiz_responses_path) do |f| %>
<%= f.hidden_field :name, value: #survey.name %>
<%= fields_for :questions do |ff| %>
<% #questions.each do |question| %>
<ul>
<%= ff.hidden_field "#{question_counter}", value: question.content %>
<%= ff.label question.content %>
<%= fields_for :answers do |fff| %>
<% question.answers.each do |answer| %>
<%= fff.hidden_field "#{answer_counter}", value: answer.content %>
<% answer_counter += 1 %>
<%= fff.label answer.content %>
<%= f.radio_button("user_answer[#{user_answer_counter}]", answer.content) %>
<% end #questions.answers.each do %>
<% end #fields_for answers %>
<% user_answer_counter += 1 %>
</ul>
<% question_counter += 1 %>
<% end ##questions.each do %>
<% end #fields_for questions %>
<%= f.submit %>
<% end #form_for%>
My wanted result is that I get a params hash with :quiz_responses containing a :questions hash, and each question value inside that hash contains an :answers hash containing answers. But this is what I see:
where there's a questions hash containing all the questions and a separate answers hash containing all the answers, and somehow user_answeris inside quiz_responses. How do I fix this mess?

You need to call fields_for on your form object like this:
<%= form_for(:quiz_responses, url: quiz_responses_path) do |f| %>
# ...
<%= f.fields_for :questions do |ff| %>
# ...
<%= ff.fields_for :answers do |fff| %>
# ...

Related

Save Question(s) form with one submit button

In my rails app I have a questions view that renders all the questions in a poll. I want to make sure that all the questions rendered can be submitted using 1 submit button.
If that's not possible, how can I render one question after another until there are no more quesitons?
The front-end code goes:
poll_question.html.erb:
<% #poll.questions.each do |qst| %>
<%= render "questions" , qst: qst%>
<p style="color: red"><%= notice %></p>
<hr>
<% end %>
Render partial _questions.html.erb:
<%= form_with model: qst.question_results.build, url: question_question_results_path(qst) do |f| %>
<% qst_type = qst.poll.voting_type %>
<% option_length = qst.options.count %>
<%= f.hidden_field :question_id, value: qst.id %>
<%= f.hidden_field :option_id, value: qst.options.first.id %>
<h3> <%= qst.title %></h3>
<h6> <%= qst.description %> </h6>
<ul>
<% qst.options.each do |option| %>
<%= f.fields_for :question_result_ranks, f.object.question_result_ranks.build do |rank_f| %>
<%= rank_f.hidden_field :option_id, value: option.id %>
<%= option.title %>
<%= rank_f.select :rank, options_for_select((1..option_length).step(1)) %><br>
<% end %>
<% end %>
</ul>
<div>
<%= f.submit "Save Answer" %>
</div>
<% end %>
Here is my routes.rb
resources :users do
resources :polls
# Questions
resources :questions, shallow: true do
resources :options
resources :question_results
patch "/create_question_results", to: "questions#create_question_results", as: "create_question_results"
end
end
Edit: These views are not rendered under the Poll and Question Controller, They are rendered under the session module which has no relationships in the model.
If you want to submit all the questions with one click, you should use a nested form.
Main template poll_question.html.erb:
<%= form_with model: #poll do |form| %>
<%= form.fields_for :questions do |f| %>
# This block renders a collection of partials.
<%= render 'question', f: %>
<% end %>
<%= form.submit 'Save' %>
<% end %>
Question form _quiestion.html.erb:
<% qst = f.object %>
<% qst_type = qst.poll.voting_type %>
<% option_length = qst.options.count %>
<%= f.hidden_field :question_id, value: qst.id %>
<%= f.hidden_field :option_id, value: qst.options.first.id %>
<h3> <%= qst.title %></h3>
<h6> <%= qst.description %> </h6>
<ul>
<% qst.options.each do |option| %>
<%= f.fields_for :question_result_ranks, f.object.question_result_ranks.build do |rank_f| %>
<%= rank_f.hidden_field :option_id, value: option.id %>
<%= option.title %>
<%= rank_f.select :rank, options_for_select((1..option_length).step(1)) %><br>
<% end %>
<% end %>
</ul>
And don't forget to add accepts_nested_attributes_for :questions in your poll model.

Quiz form submission format

I created three models, "Survey", "Question", and "Answer". Survey has_many Questions which has_many Answers (and they all belong to the model above them).
I create a quiz using this form in the SurveyController edit action. In the show action of the SurveyController, I want to take the quiz I created and generate the quiz itself for the user to take. It submits to the create action of QuizResponses controller.
<%= form_for(:quiz_responses, url: quiz_responses_path) do |f| %>
<%= hidden_field_tag :name, #survey.name %>
<% #questions.each do |question| %>
<ul>
<%= hidden_field_tag :question, question.content %>
<%= f.label question.content %>
<% question.answers.each do |answer| %>
<%= f.label answer.content %>
<%= f.radio_button(:user_answer, answer.content) %>
<% end %>
</ul>
<% end ##questions.each do %>
<%= f.submit %>
<% end #form_for%>
But it shows up in a really ugly format. How do I change the form to make it look better (IE answer text with the checkbox?
The question is too broad, but here's a simple solution:
<%= form_for(:quiz_responses, url: quiz_responses_path) do |f| %>
<%= hidden_field_tag :name, #survey.name %>
<% #questions.each do |question| %>
<%= hidden_field_tag :question, question.content %>
<!-- question title -->
<h3><%= f.label question.content %></h3>
<!-- questions answers -->
<ul>
<% question.answers.each do |answer| %>
<!-- use display:inline-block or float to make inline li -->
<li>
<%= f.label answer.content %>
<%= f.radio_button(:user_answer, answer.content) %>
</li>
<% end %>
</ul>
<% end %>
<!-- submit -->
<p>
<%= f.submit %>
</p>
<% end %>

Couldn't save collection_radio_buttons in array Ruby on Rails

We have a problem to save the values of the radio_buttons of a loop. It doesn't save in an array.
The SavedAnswer model has an has_and_belongs_to_many relation with the MultipleChoiceAnswer model.
This is my code:
<%= form_for #saved_answer do |f| %>
<% #questions.each do |question| %>
<%= collection_radio_buttons(:saved_answer, :multiple_choice_answer_ids , question.multiple_choice_answers, :id, :title) do |c| %>
<%= c.radio_button %>
<%= c.label %>
<% end %>
<% end %>
<%= f.submit "Submit" %>
<% end %>
My output is
Parameters: {"utf8"=>"✓", "authenticity_token"=>"57I9yLZMccvcb3Bn5/pw7kES0c9CUAGs33yCXoS0Urm1Yek/Baz8Hl7fO8Yl/OVZWLKsX7qrwOlqEBoXrGkcxQ==", "saved_answer"=>{ "multiple_choice_answer_ids"=>"1"}, "commit"=>"Submit"}
Thanks in advance!
You have form_for with |f| and collection with |f|.
It's not a good decision, i think. That can cause problems.
If not - write what you receive in params when trying to save.
Just use check boxes for your issue:
<%= form_for #saved_answer do |f| %>
<% #questions.each do |question| %>
<%= check_box_tag "saved_answer[multiple_choice_answer_ids][]", question.id, #saved_answer.multiple_choice_answer_ids.include?(question.id) %>
<%= question.title %>
<% end %>
<%= f.submit "Submit" %>
<% end %>
Refer: http://railscasts.com/episodes/17-habtm-checkboxes?view=asciicast

Having labels only appear once in field_for

What I currently have is:
<%= f.label :attachment_uploader, 'Current Attachments:' %>
<%= f.fields_for :data_files do |attachment| %>
<% if !attachment.object.new_record? %>
<%= attachment.label :attachment_uploader, 'Delete: ' + attachment.object.attachment_uploader_url.split("/").last %>
<%= attachment.check_box :_destroy %>
<% end %>
<% end %>
However, if I don't have any attachments the label is still there. For the sake of aesthetics I'd like it to be hidden unless I have attachments.
I was thinking something akin to:
<%= f.fields_for :data_files do |attachment, index| %>
<% if index == 0 %>
<%= attachment.label :attachment_uploader, 'Current Attachments:' %>
<% end %>
#rest of code
<% end %>
But that doesn't work!
I've read about the f.options[:index] in another post, but I couldn't figure it out.
Add an unless empty? condition before fields_for. #object will be the object for which you created the form
<%= f.label :attachment_uploader, 'Current Attachments:' %>
<% unless #object.data_files.empty? %>
<%= f.fields_for :data_files do |attachment| %>
<% if !attachment.object.new_record? %>
<%= attachment.label :attachment_uploader, 'Delete: ' + attachment.object.attachment_uploader_url.split("/").last %>
<%= attachment.check_box :_destroy %>
<% end %>
<% end %>
<% end %>

Using form_for with Awesome Nested Set

I have a Comment model with the acts_as_nested_set enabled, but when I try to do something like this (for nested comments), i receive the error "comment_comments_path not found", presumably because the default pathing doesn't work with Awesome Nested Set. How do I get around this?
<%= form_for([#comment, #comment.children.build]) do |f| %>
<%= f.text_area :content, :placeholder=>'What do you think?'%>
<%= f.submit 'Submit Reply'%>
<% end %>
I also tried this:
<%= form_for(#comment) do |f| %>
<% #comment.children.each do |sub| %>
<%= f.fields_for :children, sub do |child| %>
<%= child.text_area :content, :placeholder=>'What do you think?'%>
<%= f.submit 'Submit Reply'%>
<% end %>
<% end %>
<% end %>
but it didn't generate a textbox for me to type in.
You're very close, yeah you have to build it first then have fields for, so this:
<% #comment.children.build %>
<%= form_for([#comment]) do |f| %>
<%= f.fields_for :children do |child| %>
<%= child.text_area :content, :placeholder=>'What do you think?'%>
<% end %>
<%= f.submit 'Submit Reply'%>
<% end %>
<% end %>
This will have a form for all existing children + the new one. If you want only a form for a new child then you'll want this instead:
<%= form_for([#comment]) do |f| %>
<%= f.fields_for #comment.children.build, :children do |child| %>
<%= child.text_area :content, :placeholder=>'What do you think?'%>
<% end %>
<%= f.submit 'Submit Reply'%>
<% end %>
<% end %>

Resources