I'm trying to create a form where a user can answer questions and submit to a results page, however, when I am trying to pass the AnsweredQuestions attributes through the Quiz controller it's telling me it's an 'unknown attribute'.
Error i'm receving: unknown attribute 'answered_questions_attributes' for AnsweredQuestion.
Quiz.rb:
class Quiz < ApplicationRecord
validates :title, presence: true, length: { maximum: 50 }
has_many :questions, dependent: :destroy
has_many :answered_questions, through: :questions, dependent: :destroy
accepts_nested_attributes_for :answered_questions, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :questions, reject_if: :all_blank, allow_destroy: true
end
AnsweredQuestion.rb:
class AnsweredQuestion < ApplicationRecord
belongs_to :user
belongs_to :question
belongs_to :answer
belongs_to :quiz
end
Quiz controller:
def show
#quiz = Quiz.find(params[:id])
#questions = Question.all
#answered_questions = current_user.answered_questions.build
#quiz.answered_questions.build
end
def create
#quiz = Quiz.new(show_params)
if #quiz.save
flash[:success] = "You have created a new quiz!"
redirect_to #quiz
else
render 'new'
end
end
def post_answered_questions
#answered_question = current_user.answered_questions.build(show_params)
if #answered_question.save
flash[:success] = "You have completed the quiz!"
redirect_to results_quiz_path(params[:quiz][:id])
else
render ''
end
end
private
def user_completed_quiz
if(current_user.answered_questions.pluck(:quiz_id).uniq.include?(params[:id].to_i))
redirect_to quizzes_path
end
end
def show_params
params.require(:quiz).permit(:title, answered_questions_attributes: [:id, :answer_id, :question_id, :user_id, :quiz_id], questions_attributes: [:id, :question_title, :quiz_id, :done, :_destroy, answers_attributes: [:id, :answer_title, :question_id, :quiz_id, :correct_answer, :_destroy]])
end
end
show.html.erb (in quizzes):
<%= form_for(#quiz, url: post_answered_questions_quizzes_path, method: "POST") do |f| %>
<%= #quiz.title %>
<%= f.hidden_field :id, :value => #quiz.id %>
<% #quiz.questions.each do |question| %>
<%= f.fields_for :answered_questions do |answer_ques| %>
<h4><%= question.question_title %></h4>
<%= answer_ques.hidden_field :question_id, :value => question.id %>
<%= answer_ques.hidden_field :quiz_id, :value => #quiz.id %>
<%= answer_ques.select(:answer_id, options_for_select(question.answers.map{|q| [q.answer_title, q.id]})) %>
<% end %>
<% end %>
<%= submit_tag %>
<% end %>
UPDATED:
show.html.erb (quizzes):
<%= form_for(#answered_questions, url: answered_questions_path, method: "POST") do |f| %>
<%= #quiz.title %>
<%= f.hidden_field :id, :value => #quiz.id %>
<% #quiz.questions.each do |question| %>
<%= f.fields_for :answered_questions do |answer_ques| %>
<h4><%= question.question_title %></h4>
<%= answer_ques.hidden_field :question_id, :value => question.id %>
<%= answer_ques.hidden_field :quiz_id, :value => #quiz.id %>
<%= answer_ques.select(:answer_id, options_for_select(question.answers.map{|q| [q.answer_title, q.id]})) %>
<% end %>
<% end %>
<%= submit_tag %>
<% end %>
AnsweredQuestion controller:
class AnsweredQuestionsController < ApplicationController
def show
#answered_question = AnsweredQuestion.new
end
def create
#answered_question = current_user.answered_questions.build(answered_params)
binding.pry
if #answered_question.save
flash[:success] = "You have completed the quiz!"
redirect_to results_quiz_path(params[:quiz][:id])
else
render ''
end
end
def edit
#answered_questions = AnsweredQuestion.find(params[:id])
end
def destroy
AnsweredQuestion.find(params[:id]).destroy
flash[:success] = "Answered quiz deleted"
redirect_to answered_questions_url
end
private
def answered_params
params.require(:answered_questions).permit(:question_id, :answer_ids, :user_id, :quiz_id, :id, :_destroy)
end
end
It looks like you are accepting nested attributes for Quiz but using the nested attributes in AnsweredQuestion instead of in Quiz. You need to add accepts_nested_attributes_for in the other model and in show_params it should be quiz_attributes instead of answered_questions_attributes. Although you are using show_params twice, once over one model and the second one over the other, so you may need two params. Otherwise you'll break the other one.
Related
administrator.rb:
class Administrator < ActiveRecord::Base
has_one :administrator_role, dependent: :destroy
has_one :role, through: :administrator_role
end
role.rb:
class Role < ActiveRecord::Base
has_many :administrator_roles
has_many :administrators, through: :administrator_roles
end
administrator_role.rb:
class AdministratorRole < ActiveRecord::Base
belongs_to :administrator
belongs_to :role
end
in view for "new" action administrator_controller:
<%= form_for #administrator do |f| %>
<%= render 'shared/errors', object: #administrator %>
<div class="form-group">
<%= f.label :role_id, "Роль:" %>
<%= f.collection_select(:role_id, #roles, :id, :name) %>
</div>
...
<%= f.submit 'Save', class: 'btn btn-primary btn-lg' %>
<% end %>
administrator_controller.rb:
class AdministratorsController < ApplicationController
def new
#administrator = Administrator.new
#roles = Role.all
end
def create
#administrator = Administrator.new(administrators_params)
if #administrator.save
flash[:success] = "Account registered!"
redirect_to root_path
else
render :new
end
end
...
private
def administrators_params
params.require(:administrator).permit(:login, :password, :password_confirmation, :role_id)
end
end
when you open the page get the error:
undefined method `role_id' for #<Administrator:0x007f6ffc859b48>
Did you mean? role
How to fix it? if I put in place role_id a role, when you create administrator will get the error:
ActiveRecord::AssociationTypeMismatch (Role(#69964494936160) expected, got String(#12025960)):
You have to rewrite the form as below:
<%= form_for #administrator do |f| %>
<%= render 'shared/errors', object: #administrator %>
<div class="form-group">
<%= f.fields_for :role do |role_form| %
<%= role_form.label :role_id, "Роль:" %>
<%= role_form.select(:id, #roles.map { |role| [role.name, role.id] }) %>
<% end %>
</div>
...
<%= f.submit 'Save', class: 'btn btn-primary btn-lg' %>
<% end %>
You also need to add 1 line which enables the nested form logic as:
class Administrator < ActiveRecord::Base
has_one :administrator_role, dependent: :destroy
has_one :role, through: :administrator_role
accepts_nested_attributes_for :role
end
And also change the controller like:
class AdministratorsController < ApplicationController
#....
private
def administrators_params
params.require(:administrator).permit(
:login, :password,
:password_confirmation,
role_attributes: [ :id ]
)
end
end
When you are using has_one association, you get the below method, but not association_id=, and that is what error is saying.
association(force_reload = false)
association=(associate)
build_association(attributes = {})
create_association(attributes = {})
create_association!(attributes = {})
It's a lot of question about it all around, but I can't find the answer.
I've:
group.rb
class Group < ActiveRecord::Base
has_many :descriptions, :as => :describable
accepts_nested_attributes_for :descriptions
end
description.rb
class Description < ActiveRecord::Base
belongs_to :describable, :polymorphic => true
end
groups_controller.rb
def update
#group = Group.find(params[:id])
if #group.update_attributes(group_params)
flash[:success] = "yes"
redirect_to groups_path
else
render 'edit'
end
end
private
def group_params
params.require(:group).permit(:owner_id, :domain, descriptions_attributes: [:id, :content])
end
edit.html.erb
<%= simple_form_for #group do |f| %>
<% if #group[:domain].blank? %>
<%= f.input :domain %>
<% else %>
<%= f.input :domain, readonly: true %>
<% end %>
<%= f.input :owner_id, readonly: true %>
<%= f.simple_fields_for :descriptions do |description| %>
<%= description.input :content %>
<% end %>
<%= f.button :submit %>
<% end %>
In console I've Unpermitted parameter: description and nested attribute does not created. What should I do to save it at last?
I suppose Rails does not convert form name to names_attributes when generating form for nested polymorphic connection, this:
... description: [:content, :other_param, ...]
Works fine for me for polymorphic child.
I cannot seem to get nested attributes to save to the database, though I can see the params in terminal. I am using Rails 4.2.
Here are my models:
class Device < ActiveRecord::Base
belongs_to :hub
has_many :accessories, dependent: :destroy
accepts_nested_attributes_for :accessories,
reject_if: proc { |attributes| attributes['material'].blank? },
allow_destroy: true
end
class Accessory < ActiveRecord::Base
belongs_to :device
end
Here is the controller. I have my device model nested under user and hub model.
class DevicesController < ApplicationController
def edit
#user = User.find_by(params[:user_id])
#hub = Hub.find_by_title(params[:hub_id])
#device = Device.find_by(id: params[:id])
end
def update
#user = User.find_by(params[:user_id])
#hub = Hub.find_by_title(params[:hub_id])
#device = Device.find_by(id: params[:id])
if #device.update_attributes(device_params)
flash[:success] = "update successfully"
redirect_to user_hub_device_path(#user, #hub, #device)
else
render 'edit'
end
end
private
def device_params
params.require(:device).permit(:model, :hub_id, :resolution, :materials, :startcost, :take_online, :delivery_time, :unitcost, :color, :accessories, :accessories_attributes => [:id, :name, :cost, :color, :device_id, :_destroy])
end
end
Finally is my form.
<%= form_for([#user, #hub, #device]) do |f| %>
<fieldset>
<div id="material">
<%= f.fields_for :accessories do |a| %>
<%= render 'devices/accessory', a: a %>
<% end %>
</div>
</fieldset>
The partial:
<div class="row">
<%= a.collection_select :name, Material.all, :material, :material %>
<%= a.text_field :cost, id: "right-label" %>
<%= a.text_field :color, id: "right-label" %>
<%= a.check_box :_destroy %>
</div>
You are whitelisting params[:device][:materials] but you are checking attributes['material'].blank? (note the the s on the end). Which causes the nested attributes to be rejected.
I have these models:
class Review < ActiveRecord::Base
belongs_to :reviewable, polymorphic: true
end
class Article < ActiveRecord::Base
has_one :review, as: :reviewable, dependent: :destroy
accepts_nested_attributes_for :review
end
And a form like this:
<%= form_for #article do |f| %>
<%= f.fields_for(:review, Review.new) do |r| %>
<%= r.label :content %>
<%= r.text_field :content %>
<% end %>
<%= f.label :description %>
<%= f.text_field :description %>
<% end %>
Inside my ArticlesController I create article simple like this:
#article = Article.new(article_params)
#article.save
def article_params
params.require(:article).permit(:description, review_attributes: [:id, :content])
end
What am I doing wrong? Thank you.
Try adding accepts_nested_attributes_for
Updated:
app/models/article.rb
class Article < ActiveRecord::Base
has_one :review, as: :reviewable, dependent: :destroy
accepts_nested_attributes_for :review
end
app/controllers/articles_controller.rb
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article, notice: "Article created!"
else
render :new
end
end
private
def article_params
params.require(:article).permit(:description, review_attributes: [:content])
end
view
<%= form_for(#article) do |form| %>
<%= form.fields_for(:review_attributes, #article.build_review) do |review| %>
<%= review.label :content %>
<%= review.text_field :content %>
<% end %>
<%= form.label :description %>
<%= form.text_field :description %>
<% end %>
I have 5 Models,
Users, Jobs, Applications, Questions, and Answers
Jobs has many questions
Jobs and Users are associated through Applications
Both Questions and Applications has_many answers.
I'm trying to make an Application create action which will --
Associate a User to a particular job
Allow the user to answer the questions that the particular job has
Right now, I'm getting it to work, but it's displaying the Question and Answer Twice.
I.e The View comes out as -->
This is question one
Text field for question one
This is question two
Text field for question two
This is question one
Text field for question one
This is question two
Text field for question two
This is what my Application#New view looks like -->
<% provide(:title, " Apply to this job") %>
<%= form_for [#job, #application] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<% #job.questions.each do |question| %>
<%= f.fields_for :answers do |question_field| %>
<%= question_field.label :content, question.content %>
<%= question_field.text_area :content %>
<%= question_field.hidden_field :question_id, :value => question.id %>
<% end %>
<% end %>
<%= f.submit "Submit the application", class: "button" %>
<% end %>
This is my Application Controller ->
class ApplicationsController < ApplicationController
before_filter :set_user_and_job
def new
job = params[:job_id]
#application = Application.build(job)
end
def create
#application = Application.new(application_params)
#application.save
redirect_to root_url, :notice => "You have now applied!"
end
def edit
#application = Application.find(params[:id])
#answers = []
#job.questions.each do |question|
#application.answers.each do |answer|
#answers << answer if answer.question_id == question.id
end
end
end
def update
#application = Application.find(params[:id])
#application.update_attributes(application_params)
redirect_to root_url, :notice => "You have updated your application!"
end
def destroy
Application.find(params[:id]).destroy
flash[:success] = "Application Deleted."
redirect_to root_url
end
def show
#application = Application.find(params[:id])
#answers = []
#job.questions.each do |question|
#application.answers.each do |answer|
#answers << answer if answer.question_id == question.id
end
end
end
private
def set_user_and_job
#user = current_user
#job = Job.find(params[:job_id])
end
def application_params
params.require(:application).permit(:job_id, :user_id,
answers_attributes:[:id, :question_id, :content]).merge(user_id: current_user.id,
job_id: params[:job_id])
end
end
This is my Application Model
# == Schema Information
#
# Table name: applications
#
# id :integer not null, primary key
# user_id :integer
# job_id :integer
# created_at :datetime
# updated_at :datetime
#
class Application < ActiveRecord::Base
belongs_to :job
belongs_to :user
validates :job_id, presence: true
validates :user_id, presence: true
has_many :answers
accepts_nested_attributes_for :answers, :allow_destroy => true
def self.build(job_id)
application = self.new
job = Job.find(job_id)
job.questions.count.times do
application.answers.build
end
application
end
end
This is my edit view(fully functioning) ->
<% provide(:title, " Edit this application") %>
<%= form_for [#job, #application] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.fields_for :answers do |question_field| %>
<%= question_field.label :content, question_field.object.question.content %>
<%= question_field.text_area :content %>
<% end %>
<%= f.submit "Submit the application", class: "button" %>
<% end %>
I think the reason this is happening is that I'm running a double loop, but I'm not sure how else to also get the question id and question content for each answer.
What do you think?
--
Here's how the parameters look, when I run this form ->
<%= form_for [#job, #application] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<% #job.questions.each do |question| %>
<%= f.fields_for :answers, question do |question_field| %>
<%= question_field.label :content, question.content %>
<%= question_field.text_area :content %>
<%= question_field.hidden_field :question_id, :value => question.id %>
<% end %>
<% end %>
<%= f.submit "Submit the application", class: "button" %>
<% end %>
Started POST "/jobs/3/applications" for 127.0.0.1 at 2013-12-30 14:26:35 +0400
Processing by ApplicationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"+gbcaJJjQZ2GfkWiKcOmSf58hf/GEnWonmGrVe1p3ZI=", "application"=>{"question"=>{"content"=>"Sample answer 2", "question_id"=>"6"}}, "commit"=>"Submit the application", "job_id"=>"3"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" = '69f212609955f368c0f17873b5dce9f506bd3eb7' LIMIT 1
Job Load (0.1ms) SELECT "jobs".* FROM "jobs" WHERE "jobs"."id" = ? LIMIT 1 [["id", "3"]]
Unpermitted parameters: question
(0.1ms) begin transaction
Try this:
<% #job.questions.each do |question| %>
<%= f.fields_for :answers, question do |question_field| %>
<%= question_field.label :content, question.content %>
<%= question_field.text_area :content %>
<%= question_field.hidden_field :question_id, :value => question.id %>
<% end %>
<% end %>
This should split up the f.fields_for call into different instances of the object
I think you're basically cycling through the questions, which is then showing all the fields, whereas if you make it work for a single instance, it will just show the answer for that question
Maybe Try has_many :through
Maybe we need to implement has_many :through on the answers fields, so that we can create an answer for each question, like this (sorry if I got some associations incorrect):
#app/models/question.rb
Class Question < ActiveRecord::Base
belongs_to :job
has_one :answer
accepts_nested_attributes_for :answer
end
#app/models/answer.rb
Class Answer < ActiveRecord::Base
belongs_to :question
belongs_to :user
end
#app/models/application.rb
Class Application < ActiveRecord::Base
belongs_to :user
belongs_to :job
has_many :questions, through: job #-> maybe
has_many :answers, through: :questions #-> maybe
accepts_nested_attributes_for :questions
def self.build(job_id)
application = self.new
job = Job.find(job_id)
job.questions.count.times do
application.questions.build.build_answer
end
application
end
end
#app/models/job.rb
Class Job < ActiveRecord::Base
has_many :questions
has_many :applications
has_many :answers, through: :applications
has_many :users, through: :applications
end
This will give you this view:
<%= form_for #application do |f| %>
<%= f.fields_for :questions do |q| %>
<%= q.label :content %>
<%= q.fields_for :answer do |a| %>
<%= a.text_area :content %>
<% end %>
<% end %>
<% end %>
You'd have to change your controller to handle the new associations like this:
#app/controllers/applications_controller.rb
def new
job = params[:job_id]
#application = Application.build(job)
end
private
def application_params
params.require(:application).permit(:job_id, :user_id,
questions_attributes: [answer_attributes:[:content]]).merge(user_id: current_user.id,
job_id: params[:job_id])
end