Rails Strong Params & Nested Forms: "Unpermitted parameter: answer" - ruby-on-rails

I have an Assessment model which has many questions and many answers through questions
class Assessment < ActiveRecord::Base
belongs_to :template
belongs_to :patient
has_many :questions, :through=> :template
has_many :answers, :through=> :questions
accepts_nested_attributes_for :answers
end
class Question < ActiveRecord::Base
belongs_to :template
has_many :answers
end
class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :assessment
end
I want to create an assessment form which can accept nested attributes for answers.
Here's my assessment form:
<%= form_for #assessment do |f| %>
<div role="tabpanel" class="tab-pane active" id="subjective">
<% #assessment.questions.each do |question| %>
<%= render 'question_fields', :question=> question, :f=> f %>
<% end %>
</div>
<%= f.hidden_field :patient_id, :value=> #assessment.patient.id %>
<%= f.hidden_field :template_id, :value=> #assessment.id %>
<%= f.submit 'Save', :class=> "btn btn-primary", :style=>"width: 100%;" %>
<% end %>
And my question_fields:
<p><%= question.content %></p>
<%= f.fields_for :answer do |builder| %>
<div class="row">
<div class="col-sm-10 question">
<% if question.field_type == "text_area" %>
<%= builder.text_area :content, :class=>"form-control" %>
<% end %>
</div>
</div>
And finally my action:
def create
#assessment = current_user.assessments.new(assessment_params)
if #assessment.save
redirect_to assessments_path
else
render :new
end
end
protected
def assessment_params
params.require(:assessment).permit(
:template_id, :patient_id,
:answers_attributes => [:id, :question_id, :assessment_id, :tracking, :content])
end
When I submit my form, I get taken to the assessments_path, but my log shows "unpermitted params answer". I know somewhere I've gone wrong with my pluralization or associations, but not sure exactly where.

Give this a shot, it looks like you're accepts_nested_attributes_for :answers is in the wrong place and you're missing the one for questions.
class Assessment < ActiveRecord::Base
belongs_to :template
belongs_to :patient
has_many :questions, :through=> :template
has_many :answers, :through=> :questions
accepts_nested_attributes_for :questions
end
class Question < ActiveRecord::Base
belongs_to :template
has_many :answers
accepts_nested_attributes_for :answers
end
class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :assessment
end

Related

using has_many through with dynamic forms rails 4

I want to create an appointment form with dynamics forms. But I'm not getting what I'm doing wrong
I'm having trouble with the partial _appointment_record_form_fields and with appointment_controller.
Someone can help me fix the controller and the view?
My Models:
class Appointment < ActiveRecord::Base
has_many :appointment_record_forms, dependent: :destroy
has_many :record_forms, through: :appointment_record_forms
accepts_nested_attributes_for :appointment_record_forms, allow_destroy: true
end
class AppointmentRecordForm < ActiveRecord::Base
belongs_to :appointment
belongs_to :record_form
serialize :properties, Hash
def validate_properties
record_form.record_form_fields.each do |record_form_field|
if record_form_field.required? && properties[record_form_field.name].blank?
errors.add record_form_field.name, "must not be blank"
end
end
end
end
class RecordForm < ActiveRecord::Base
has_many :record_form_fields
has_many :appointment_record_forms, dependent: :destroy
has_many :appointments, through: :appointment_record_forms
accepts_nested_attributes_for :record_form_fields, allow_destroy: true
end
class RecordFormField < ActiveRecord::Base
belongs_to :record_form
end
My Controller
class AppointmentsController < ApplicationController
.
.
.
def appointment_params
params.require(:appointment).permit(:duration, :appointment_date, :patient_id, :doctor_id,
:record_forms => [:id, :name, :_destroy],
:record_form_fields => [:id, :name, :field_type, :require, :record_form_id, :_destroy])
end
end
Views:
views/appointment/_form
...
<%= f.fields_for :appointment_record_forms do |builder| %>
<%= render 'appointment_record_form_fields', f: builder %>
<% end %>
<%= link_to_add_fields "Add Field", f, :appointment_record_forms %>
...
partial/_appointment_record_form_fields
<fieldset>
<%= f.fields_for :properties, OpenStruct.new(#appointment_record_forms.properties) do |builder| %>
<% #appointment_record_forms.record_form.record_form_fields.each do |record_form_field| %>
<%= render "appointments/fields/#{record_form_field.field_type}", record_form_field: record_form_field, f: builder %>
<% end %>
<% end %>
<%= f.hidden_field :_destroy %>
<%= link_to "remove", '#', class: "remove_fields" %>
</fieldset>
TKS

How to handle multiple models in one rails form?

I have the following models
class Survey < ActiveRecord::Base
has_many :survey_sections
accepts_nested_attributes_for :survey_sections
end
class SurveySection < ActiveRecord::Base
belongs_to :survey
has_many :questions
accepts_nested_attributes_for :questions
end
class Question < ActiveRecord::Base
belongs_to :survey_section
has_many :answers
belongs_to :question_group
accepts_nested_attributes_for :question_group
accepts_nested_attributes_for :answers
end
class Answer < ActiveRecord::Base
belongs_to :question
end
class QuestionGroup < ActiveRecord::Base
has_many :questions
end
My Controller:
def new
#survey = Survey.new
survey_section = #survey.survey_sections.build
survey_section.questions.build
end
def create
#survey = Survey.new(survey_params)
if #survey.save
redirect_to #survey, notice: 'Super'
else
render 'new'
end
end
def survey_params
params.require(:survey).permit(:title, :description, survey_sections_attributes:[:id, :title, questions_attributes:[:id, :text, answers_attributes:[:id, :text]]])
end
How it is possible to save data in more then 3 models?
At the moment i can save from my survey form data into the survey, survey section and question model. But i don't know what i have to in the controller that i can save data into the other models.
You can handle as many forms as you need, if you use the fields_for helper properly.
This is where you're falling short I think (your controller seems okay).
I also wrote an answer about this some time back.
#app/models/survey.rb
class Survey < ActiveRecord::Base
has_many :sections
accepts_nested_attributes_for :sections
end
#app/models/section.rb
class Section < ActiveRecord::Base
belongs_to :survey
has_many :questions
accepts_nested_attributes_for :questions
end
#app/models/question.rb
class Question < ActiveRecord::Base
belongs_to :section
has_many :answers
end
Try and keep your model names as succinct as possible.
#app/controllers/surveys_controller.rb
class SurveysController < ApplicationController
def new
#survey = Survey.new
#survey.sections.build.questions.build
end
def create
#survey = Survey.new survey_params
#survey.save
end
private
def survey_params
params.require(:survey).permit(:title, sections_attributes: [:title, questions_attributes:[:title]])
end
end
#app/views/surveys/new.html.erb
<%= form_for #survey do |f| %>
<%= f.text_field :title %>
<%= f.fields_for :sections do |section| %>
<%= section.text_field :title %>
<%= section.fields_for :questions do |question| %>
<%= question.text_field :title %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
You can get best explanation here with same type of model
http://railscasts.com/episodes/196-nested-model-form-part-1
#app/models/survey.rb
class Survey < ActiveRecord::Base
has_many :sections, :dependent => :destroy
accepts_nested_attributes_for :sections, :allow_destroy => true
end
#app/models/section.rb
class Section < ActiveRecord::Base
belongs_to :survey
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :allow_destroy => true
end
#app/models/question.rb
class Question < ActiveRecord::Base
belongs_to :section
has_many :answers
end
now in controller
def new
#survey = Survey.new
section = #survey.sections.build
section.questions.build
end
end
Now in views
<%= form_for #survey do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<%= f.fields_for :sections do |builder| %>
<%= builder.text_field :title %>
<%= builder.fields_for :questions do |question| %>
<%= question.text_field :content%>
<% end %>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>

Rails fields_for params blank

I'm trying to build a nested form for a survey and having problems with my params hash missing values from within the fields_for block.
I have the following models. The way the app works is that an admin creates a MiniPost and its MiniPostQuestions. Then a client creates a new MiniPostSurvey using one of the MiniPosts. The client then emails out SurveyInvites to users. When a user responds, a new SurveyResponse is created, along with a new QuestionAnswer for each MiniPostQuestion in the survey.
class MiniPost < ActiveRecord::Base
has_many :mini_post_questions
has_many :question_answers, through: :mini_post_questions
has_many :mini_post_surveys
belongs_to :employer
def questions
mini_post_questions
end
def surveys
mini_post_surveys
end
end
class MiniPostQuestion < ActiveRecord::Base
has_many :question_answers
belongs_to :mini_post
belongs_to :employer
def answers
question_answers
end
end
class MiniPostSurvey < ActiveRecord::Base
belongs_to :mini_post
belongs_to :employer
belongs_to :company
has_many :survey_invites
has_many :survey_responses, through: :survey_invites
def questions
mini_post.questions
end
end
class SurveyInvite < ActiveRecord::Base
belongs_to :mini_post_survey
has_many :survey_responses
def responses
survey_responses
end
end
class SurveyResponse < ActiveRecord::Base
belongs_to :survey_invite
has_many :question_answers
has_many :mini_post_questions, through: :question_answers
end
class QuestionAnswer < ActiveRecord::Base
belongs_to :survey_response
belongs_to :mini_post_question
validates :answer, presence: true
end
Here is my response form.
<div class="form-box">
<%= form_for #response, url: "/survey?key=#{#invite.key}", method: :post, html: { role: 'form' } do |f| %>
<% #questions.each do |question| %>
<div class="form-group">
<%= f.fields_for :mini_post_questions, question do |q| %>
<%= q.fields_for :question_answers, question.question_answers.build do |a| %>
<%= f.label question.question %>
<%= a.text_area :answer, class: 'form-control' %>
<%= a.hidden_field :survey_response_id, value: #survey.id %>
<% end %>
<% end %>
</div>
<% end %>
<div><%= f.submit "Submit", :class => "btn btn-primary" %></div>
<% end %>
</div>
My form renders correctly, however when I submit it, my params hash looks like this:
{"utf8"=>"✓",
"authenticity_token"=>"p8Tky2So10TH4FUUvLKhIh7j2vjNN39b3HDsF0cYE14=",
"survey_response"=>{"mini_post_questions"=>{"question_answers"=>{"answer"=>"", "survey_response_id"=>"11"}}},
"commit"=>"Submit",
"key"=>"e4fab42244db2286d471082696",
"controller"=>"surveys",
"action"=>"create"}
I would expect a mini_post_question key for each question, but I'm not sure how to get to that point.
I think you are on the right track, but you need to have your models accept nested attributes for the objects that you want in your form.
So I think in your SurveyResponse model, you would have
class SurveyResponse < ActiveRecord::Base
belongs_to :survey_invite
has_many :question_answers
accepts_nested_attributes_for :question_answers
has_many :mini_post_questions, through: :question_answers
end
Also, since it looks like you are not modifying the mini question here, I would say that you don't need to accept nested attributes for the questions, but just have a hidden field that assigns the mini_question_id to the question_answer
So your form should be something like this
<div class="form-box">
<%= form_for #response, url: "/survey?key=#{#invite.key}", method: :post, html: { role: 'form' } do |f| %>
<% #questions.each do |question| %>
<div class="form-group">
<%= f.fields_for :question_answers, #survey.question_answers.build do |q| %>
<%= q.label question.question %>
<%= q.text_area :answer, class: 'form-control' %>
<%= q.hidden_field :mini_post_question_id, value: question.id %>
<% end %>
</div>
<% end %>
<div><%= f.submit "Submit", :class => "btn btn-primary" %></div>
<% end %>
</div>
Since your form is accepting nested attributes for question_answers, you won't need to supply the survey_id.
This should get you closer to what you would need in your form.

Rails uninitialized constant for an association

So there is a plethora of questions about the "uninitialized constant" error, and it's almost always due to an incorrectly specified association (e.g. plural model names instead of singular, incorrectly writing your association inside the model, etc). My models and form look spotless, so maybe this is something new (or I'm blind)?
A "user" has one "move". A "move" has many "neighborhood_preferences", and through this, many "neighborhoods".
Models:
class User < ActiveRecord::Base
has_one :move
accepts_nested_attributes_for :move, allow_destroy: true
end
class Move < ActiveRecord::Base
belongs_to :user
has_many :neighborhood_preferences
has_many :neighborhoods, through: :neighborhood_preferences
accepts_nested_attributes_for :neighborhood_preferences, allow_destroy: true
end
class NeighbhoodPreference < ActiveRecord::Base
belongs_to :neighborhood
belongs_to :move
end
class Neighborhood < ActiveRecord::Base
belongs_to :city
has_many :neighborhood_preferences
has_many :moves, through: :neighborhood_preferences
end
View:
<%= simple_form_for(#user, :html => { class: :form } ) do |u| %>
<%= u.fields_for :move do |m| %>
<div>
<%= m.label :start_date %>
<%= m.date_field :start_date %>
</div>
<div>
<%= m.label :end_date %>
<%= m.date_field :end_date %>
</div>
<div>
<%= m.label :min_price %>
<%= m.text_field :min_price %>
</div>
<div>
<%= m.label :max_price %>
<%= m.text_field :max_price %>
</div>
<%= m.association :neighborhood_preferences %>
<% end %>
<%= u.submit "Save Changes" %>
<% end %>
There is a typo in class name NeighbhoodPreference.

ruby on rails - presenting many to many relation

I have recipe and ingredient in a many to many relation.
I have defined the following commands in my presentation.
<div>
<%= render :partial => 'ingredients/form',
:locals => {:form => recipe_form} %>
</div>
the partial begins with
<%= form_for(#ingredient) do |ingredient_form| %>
but received #ingredient nill.
Then I tried
<%= recipe_form.fields_for :ingredients do |builder| %>
<%= render 'ingredient_fields', f: builder %>
<% end %>
where my render was
<p class="fields">
<%= f.text_field :name %>
<%= f.hidden_field :_destroy %>
</p>
but nothing was printed.
then I tried
<% #recipe.ingredients.each do |ingredient| %>
<%= ingredient.name %>
<% end %>
and only then all of the ingredients were printed.
What was I doing wrong in the previous tries ?
Thank you.
my ingredient recipe relation defined as follows
class Ingredient < ActiveRecord::Base
has_many :ingredient_recipes
has_many :recipes, :through => :ingredient_recipes
...
class Recipe < ActiveRecord::Base
has_many :ingredient_recipes
has_many :ingredients, :through => :ingredient_recipes
...
accepts_nested_attributes_for :ingredient_recipes ,:reject_if => lambda { |a| a[:content].blank?}
class IngredientRecipe < ActiveRecord::Base
attr_accessible :created_at, :ingredient_id, :order, :recipe_id
belongs_to :recipe
belongs_to :ingredient
end
You don't exactly specify what you are trying to do, so I am presuming you have a page that shows a recipe, with many ingredients that can be edited and added to. In your controller you have something like:
class RecipeController < ApplicationController
def edit
#recipe = Recipe.find(params[:id]
end
end
I am also presuming that you are looking to have a form that post backs to the create action. I therefore think you want a form like this:
<%= form_for #recipe do |form| %>
<%= label_for :name %>
<%= text_field :name %>
<%= form.fields_for :ingredients do |ingredients_fields| %>
<div class="ingredient">
<%= f.text_field :name %>
<%= f.hidden_field :_destroy %>
</div>
<% end %>
<% end %>
Also, change your recipe to accept nested attributes for ingredients, not ingredient_recipes:
class Recipe < ActiveRecord::Base
has_many :ingredient_recipes
has_many :ingredients, :through => :ingredient_recipes
...
accepts_nested_attributes_for :ingredients, :reject_if => lambda { |a| a[:content].blank?}
And finally, add attr_accessible for your content:
class Ingredient < ActiveRecord::Base
attr_accessible :content
...
Does that work for you?

Resources