I have two models: Question and Options. Question has has_many relation with Options. I need to add options to question whenever I create a new question. I have written the code but I am not able to send data to the options of Question model. Whenever I create the question and add options in the form, the options to that question are empty. Where is the mistake?
Models
class Question < ApplicationRecord
belongs_to :user
has_many :options
accepts_nested_attributes_for :options
end
class Option < ApplicationRecord
belongs_to :question
end
questions_controller.rb
# GET /questions/new
def new
#question = Question.new
#question.options.build(params[:options])
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
#question = Question.new(question_params)
puts("---------------------Question options: --------------------------------------------")
puts(#question.options)
#question.user = current_user
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1
# PATCH/PUT /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
_form.html.erb
<%= form_with(model: question, local: true) do |form| %>
<% if question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% question.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
<%= form.fields_for :address do |a| %>
<div class="field">
<%= a.label :option1 %>
<%= a.text_area :body %>
</div>
<div class="field">
<%= a.label :option2 %>
<%= a.text_area :body %>
</div>
<% end %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
For this case, I strongly recommend using a FormObject in place of accepts_nested_attributes_for. Here is a quick video on how to implement a FormObject. https://thoughtbot.com/upcase/videos/form_objects
Also, there is a related discussion here on why accepts_nested_attributes_for is not a great option.
Related
I've created a basic devise login with microposts which have :user_id from :users, and t.text :content. If it matters I generated this with a scaffold content:text. Here is the micropost controller:
class MicropostsController < ApplicationController
def new
#micropost = Micropost.new
end
def create
#micropost = Micropost.create(params[:content])
respond_to do |format|
if #micropost.save!
format.html { redirect_to microposts_path, notice: 'Micropost was successfully created.' }
format.json { render :show, status: :created, location: #micropost }
else
format.html { render :new }
format.json { render json: #micropost.errors, status: :unprocessable_entity }
end
end
end
private
def micropost_params
params.require(:micropost).permit( :content)
end
end
However everytime I try and create/save a 'micropost' is results in 'unpermitted parameter:text'? Any help is appreciated.
_form.html.erb
<%= form_with(model: micropost, local: true) do |form| %>
<% if micropost.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(micropost.errors.count, "error") %> prohibited this micropost from being saved:</h2>
<ul>
<% micropost.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.text_field :text %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
The field in your form is text but your fields name is content. Change the text field in your form to :content.
This was just laziness on my part, the micropost new.html.erb had no form.label or form.text_are, additionally #micropost = Micropost.create was typed wrong as #micropost.create. Sorry guys!
I'm making a survey app, I've got 3 models: Survey, Question, and Answer. Survey has_many questions, Question has_many answers.
I've got two main errors:
My code is supposed to generate 4 answer fields for each question but only 1 answer field is generated.
When I press submit on my form, I get
unknown attribute 'answers' for Survey.
Extracted source (around line #33):
# POST /surveys.json
def create
#survey = Survey.new(survey_params)
respond_to do |format|
if #survey.save
I think the second problem is related to the answers model in some way but I'm not sure how. Here's my code:
surveys_controller:
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
# GET /surveys
# GET /surveys.json
def index
#surveys = Survey.all
end
# GET /surveys/1
# GET /surveys/1.json
def show
end
# GET /surveys/new
def new
#survey = Survey.new
3.times do
question = #survey.questions.build
4.times { question.answers.build }
end
end
# GET /surveys/1/edit
def edit
end
# POST /surveys
# POST /surveys.json
def create
#survey = Survey.new(survey_params)
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render :show, status: :created, location: #survey }
else
format.html { render :new }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /surveys/1
# PATCH/PUT /surveys/1.json
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { render :show, status: :ok, location: #survey }
else
format.html { render :edit }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# DELETE /surveys/1
# DELETE /surveys/1.json
def destroy
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url, notice: 'Survey was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_survey
#survey = Survey.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def survey_params
params.require(:survey).permit!
end
end
surveys/_form.html.erb
<%= form_for(#survey) do |f| %>
<% if #survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% #survey.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :questions do |builder| %>
<p>
<%= builder.label :content, "Question" %><br />
<%= builder.text_area :content, :rows => 3 %>
</p>
<%= f.fields_for :answers do |builder| %>
<p>
<%= builder.label :content, "Answer" %>
<%= builder.text_field :content %>
</p>
<% end %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
surveys/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= #survey.name %>
</p>
<ol>
<% #survey.questions.each do |question| %>
<li><%= question.content %>
<ul>
<% for answer in question.answers %>
<li><%= answer.content %></li>
<% end %>
</ul>
</li>
<% end %>
</ol>
<%= link_to 'Edit', edit_survey_path(#survey) %> |
<%= link_to 'Back', surveys_path %>
survey.rb:
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions, :reject_if => -> (a) {a[:content].blank? }, :allow_destroy => true
end
question.rb:
class Question < ActiveRecord::Base
belongs_to :survey
has_many :answers, :dependent => :destroy
accepts_nested_attributes_for :answers, :reject_if => -> (a) {a[:content].blank? }, :allow_destroy => true
end
answer.rb
class Answer < ActiveRecord::Base
belongs_to :question
end
Any help would be appreciated, I've been stuck on this for hours now!
I don't know if the errors could be related to the fields_for, what happens when you do:
<%= f.fields_for :questions do |question_attribute| %>
<p>
<%= question_attribute.label :content, "Question" %><br />
<%= question_attribute.text_area :content, :rows => 3 %>
</p>
<%= question_attribute.fields_for :answers do |answer_attribute| %>
<p>
<%= answer_attribute.label :content, "Answer" %>
<%= answer_attribute.text_field :content %>
</p>
<% end %>
<% end %>
Let me know what is the outcome of that.
Everything looks great as far as I can tell -- but the contents for the field_for nested form aren't displaying the 3 question forms I want. Why?
survey.rb
class Survey < ActiveRecord::Base
has_many :questions, :dependent => :destroy
accepts_nested_attributes_for :questions
end
question.rb
class Question < ActiveRecord::Base
belongs_to :survey
end
surveys_controller.rb
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
# GET /surveys
# GET /surveys.json
def index
#surveys = Survey.all
end
# GET /surveys/1
# GET /surveys/1.json
def show
end
# GET /surveys/new
def new
#survey = Survey.new
3.times { #survey.questions.build }
end
# GET /surveys/1/edit
def edit
end
# POST /surveys
# POST /surveys.json
def create
#survey = Survey.new(survey_params)
respond_to do |format|
if #survey.save
format.html { redirect_to #survey, notice: 'Survey was successfully created.' }
format.json { render :show, status: :created, location: #survey }
else
format.html { render :new }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /surveys/1
# PATCH/PUT /surveys/1.json
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { render :show, status: :ok, location: #survey }
else
format.html { render :edit }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# DELETE /surveys/1
# DELETE /surveys/1.json
def destroy
#survey.destroy
respond_to do |format|
format.html { redirect_to surveys_url, notice: 'Survey was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_survey
#survey = Survey.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def survey_params
params.require(:survey).permit(:name)
end
end
surveys/new.html.erb
<h1>New Survey</h1>
<%= render 'form' %>
<%= link_to 'Back', surveys_path %>
surveys/_form.html.erb
<%= form_for(#survey) do |f| %>
<% if #survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% #survey.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<% f.fields_for :questions do |builder| %>
<p>
<%= builder.label :content, "Question" %><br />
<%= builder.text_area :content, :rows => 3 %>
</p>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Can't believe I did this -- was missing <%= on fields_for
It creates the object, says that it was successfully created, but all fields are saved in the database with nil values. Only created_at and updated_at are saved normally.
Some methods of my controllers/admin/categories_controller.rb
def new
#admin_category = Category.new
end
# GET /admin/categories/1/edit
def edit
end
# POST /admin/categories
# POST /admin/categories.json
def create
#admin_category = Category.new(params[:category])
respond_to do |format|
if #admin_category.save
format.html { redirect_to admin_category_path(#admin_category), notice: 'Category was successfully created.' }
format.json { render :show, status: :created, location: admin_category_path(#admin_category) }
else
format.html { render :new }
format.json { render json: #admin_category.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /admin/categories/1
# PATCH/PUT /admin/categories/1.json
def update
respond_to do |format|
if #admin_category.update(admin_category_params)
format.html { redirect_to #admin_category, notice: 'Category was successfully updated.' }
format.json { render :show, status: :ok, location: #admin_category }
else
format.html { render :edit }
format.json { render json: #admin_category.errors, status: :unprocessable_entity }
end
end
end
This is my models/category model:
class Category < ActiveRecord::Base
belongs_to :category
end
This is my routes.br file
namespace :admin do
resources :categories
end
My views/admin/categories/_form.html.erb
<%= form_for(#admin_category, url: admin_categories_path) do |f| %>
<% if #admin_category.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#admin_category.errors.count, "error") %> prohibited this admin_category from being saved:</h2>
<ul>
<% #admin_category.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :is_active %><br>
<%= f.check_box :is_active %>
</div>
<div class="field">
<%= f.label :main_menu %><br>
<%= f.check_box :main_menu %>
</div>
<div class="field">
<%= f.label :category_id %><br>
<%= f.number_field :category_id %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And when I try to edit, I get this error:
No route matches [PATCH] "/admin/categories"
I'm very newbie to Ruby on Rails, so I would apreciate any help!
Thanks!
You are only passing :category when creating a new Category:
def create
#admin_category = Category.new(params[:category])
Change it to Category.new(user_params) and try again. This will pass on all parameters you're creating and feed it to the database.
Also, permit the parameters you are trying to pass:
def user_params
params.require(:admin_category).permit(:name, :is_active, :main_menu, :category_id)
end
Strong Params:
#app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
def create
#admin_category = Category.new category_params
end
private
def category_params
params.require(:category).permit(:name, :is_active, :main_menu, :category_id)
end
end
--
As a tip, if you're using nested objects with forms, you can pass both objects in an array to create the nested path:
#app/views/admin/categories/new.html.erb
<%= form_for [:admin, #admin_category] do |f| %>
I have a rails form to collect information on people for a family tree application. There are two drop down boxes that are used to assign the parents of the person being edited/created, however when a selection is made in either, or both, of these boxes, it is not committed to the database. It doesn't throw any exceptions, however when I check the database, the fatherID and motherID fields remain as null.
Here is the complete code for the form:
Does anybody have any ideas where I'm going astray?
Thanks.
<%= form_for(#person) do |f| %>
<% if #person.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#person.errors.count, "error") %> prohibited this person from being saved:</h2>
<ul>
<% #person.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :FirstName %><br>
<%= f.text_field :FirstName %>
</div>
<div class="field">
<%= f.label :LastName %><br>
<%= f.text_field :LastName %>
</div>
<div class="field">
<%= f.label :MaidenName %><br>
<%= f.text_field :MaidenName %>
</div>
<div class="field">
<%= f.label :Sex %><br>
<%= f.select(:Sex, options_for_select([['Male', 'M'], ['Female', 'F']]))%>
</div>
<div class="field">
<p>Parents:</p>
Mother: <%= select(:motherID, options_from_collection_for_select(Person.all, :id, :FirstName), :include_blank => true)%>
Father: <%= select(:fatherID, options_from_collection_for_select(Person.all, :id, :FirstName), :include_blank => true)%>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Controller code
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
# GET /people
# GET /people.json
def index
#people = Person.all
end
# GET /people/1
# GET /people/1.json
def show
end
# GET /people/new
def new
#person = Person.new
end
# GET /people/1/edit
def edit
end
# POST /people
# POST /people.json
def create
#person = Person.new(person_params)
respond_to do |format|
if #person.save
format.html { redirect_to #person, notice: 'Person was successfully created.' }
format.json { render action: 'show', status: :created, location: #person }
else
format.html { render action: 'new' }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /people/1
# PATCH/PUT /people/1.json
def update
respond_to do |format|
if #person.update(person_params)
format.html { redirect_to #person, notice: 'Person was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# DELETE /people/1
# DELETE /people/1.json
def destroy
#person.destroy
respond_to do |format|
format.html { redirect_to people_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_person
#person = Person.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def person_params
params.require(:person).permit(:FirstName, :LastName, :MaidenName, :Sex)
end
end
Model Code
class Person < ActiveRecord::Base
has_ancestry
end
:motherID and :fatherID need to be in params.require(:person).permit(:FirstName, :LastName, :MaidenName, :Sex) otherwise the controller does not pass these values to the model for them to be saved.
For more information about strong parameters, see the rails guide: http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters