I have an app where users
can create their own forms
and then apply them to their own clients
The forms
are created dynamically, meaning users can add as many questions
they want, and each question has many choices
(think of a survey structure).
So far so good, now I'm struggling when applying the forms, specifically getting the answers
saved, persisted and showing properly when rendering the edit
view.
When rendering the edit
view, each question has their choices multiplied by how many questions/answers the answered_form has (I don't know exactly which of them, I am guessing here).
Answers
are persisted to database, although each question has their choices multiplied, the selected answer is checked and is checked in the collection of the original answer. (answer one checked in the first 3 choices, answer two in the second 3 choices, answer three in the third 3 choices and answer four in the forth 3 choices)
I've read 2 similar questions here in SO, RoR nested attributes produces duplicates when edit , and Nested form update action producing duplicate results , but I already have the :id
in strong parameters (you can see it in the code below).
I want to make myself clear here: creating the form, with nested question and nested choices is working perfectly fine, and also editing the created form. The struggle is when USING, ANSWERING or APPLYING it in the APP.
Code:
_form.html.erb:
<%= form_for [@child, @answered_form] do |f| %>
<%= f.hidden_field :form_id %>
<%= f.hidden_field :child_id %>
<div class="answered_form">
<h1><%= @form.f_title %></h1>
<h3><%= @form.f_description %></h3>
<br>
<% questions = @form.questions %>
<% i = 1 %>
<% questions.each do |question| %>
<%= i.to_s + ". " %><%= question.q_title %>
<br />
<% choices = question.choices %>
<%= f.fields_for :answers do |a| %>
<% choices.each do |choice| %>
<%= a.radio_button :a_content, choice.c_description %>
<%= a.label :a_content, choice.c_description, :value => choice.c_description, class: 'no-margin' %>
<br />
<% end %>
<% end %>
<br />
<% i += 1 %>
<% end %>
</div>
<div class="text-center">
<%= f.submit yield(:button_text), class: "btn btn-primary btn-lg" %>
</div>
<% end %>
answered_forms_controller.rb:
class AnsweredFormsController < ApplicationController
before_action :correct_answered_form, only: [:edit, :update, :destroy]
def new
@child = current_user.children.find(params[:child_id])
@form = current_user.forms.find(params[:form_id])
@answered_form = @child.answered_forms.new(form_id: params[:form_id])
@answered_form.answers.build
end
def create
@answered_form = AnsweredForm.create(answered_form_params)
if @answered_form.save
flash[:success] = "New survey " + @answered_form.form.f_title + " applied to patient!"
redirect_to current_user.children.find(params[:child_id])
else
render 'new'
end
end
def edit
@child = current_user.children.find(params[:child_id])
@form = current_user.forms.find(params[:form_id])
end
def update
if @answered_form.update_attributes(answered_form_params)
flash[:success] = "Survey updated!"
redirect_to @answered_form.child
else
render 'edit'
end
end
def show
end
def destroy
@child = current_user.children.find(params[:child_id])
@form = current_user.forms.find(params[:form_id])
@answered_form.destroy
redirect_to :back
end
private
# Strong params for creating and updating forms
def answered_form_params
params.require(:answered_form).permit(:form_id, :child_id, answers_attributes: [:id, :a_content, :a_boolean, :_destroy, :choice_id])
end
# Confirms the correct answered_form
def correct_answered_form
@answered_form = AnsweredForm.find(params[:id])
end
end
Logs: POST:
Started POST "/children/1-juan-gomez-pereira/answered_forms" for ::1 at 2016-07-08 11:55:01 -0400
Processing by AnsweredFormsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"hFrRfEwVG4XSkdbPwrohm1QEQ0FtE/as3sM2Fj3Av3reVHJxZBVKPeuAeD713H7gVyZn7eppnULDhLJQz+EBeg==", "answered_form"=>{"form_id"=>"1", "child_id"=>"1", "answers_attributes"=>{"0"=>{"a_content"=>"Bajo"}, "1"=>{"a_content"=>"Sí"}, "2"=>{"a_content"=>"Derecha"}, "3"=>{"a_content"=>"Pesado"}}}, "commit"=>"Aplicar", "child_id"=>"1-juan-gomez-pereira"}
PATCH:
Started PATCH "/children/1-juan-gomez-pereira/answered_forms/3" for ::1 at 2016-07-08 11:55:54 -0400
Processing by AnsweredFormsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"oGdqgUR95HMkMff40Gq1zWar/CH64F0jsN3oRHT1q/H6acmMbH21yx0gWQnnDOq2ZYnYjX2aNs2tmmwChtQV8Q==", "answered_form"=>{"form_id"=>"1", "child_id"=>"1", "answers_attributes"=>{"0"=>{"a_content"=>"Bajo", "id"=>"9"}, "1"=>{"a_content"=>"Bajo", "id"=>"10"}, "2"=>{"a_content"=>"Bajo", "id"=>"11"}, "3"=>{"a_content"=>"Confuso", "id"=>"12"}, "4"=>{"a_content"=>"No", "id"=>"9"}, "5"=>{"a_content"=>"Sí", "id"=>"10"}, "6"=>{"a_content"=>"Confuso", "id"=>"11"}, "7"=>{"a_content"=>"Confuso", "id"=>"12"}, "8"=>{"a_content"=>"Confuso", "id"=>"9"}, "9"=>{"a_content"=>"Izquierda", "id"=>"10"}, "10"=>{"a_content"=>"Confuso", "id"=>"11"}, "11"=>{"a_content"=>"Izquierda", "id"=>"12"}, "12"=>{"a_content"=>"Liviano", "id"=>"9"}, "13"=>{"a_content"=>"Liviano", "id"=>"10"}, "14"=>{"a_content"=>"Pesado", "id"=>"11"}, "15"=>{"a_content"=>"Liviano", "id"=>"12"}}}, "commit"=>"Actualizar", "child_id"=>"1-juan-gomez-pereira", "id"=>"3"}
I noticed that when POST, the id
for answer is not passed as a parameter. If I check the console, I can see that answer was created properly.
I think this line could be the problem
<% choices.each do |choice| %>
If you have built question.answers
, you can iterate on them only using f.fields_for :answers
and skip the above line. I assume choices
are not much different from answers
.
Please clear me if i am wrong.
So the problem was in this line of the code:
<%= f.fields_for :answers do |a| %>
fields_for helper generates fields for the entire collection of the object for whom your are calling it.
In this case, @answered_form
had 4 answers
after creating it, so when calling fields_for in edit, it was generating 4 fields set for each question.
To solve this, you need to specify a collection that fits your needs and pass it through the fields_for helper:
<%= f.fields_for :answers, ANSWERS_COLLECTION do |a| %>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.