创建、编辑和更新不适用于 Rails 4.2 中第一层嵌套形式的第三层对象
Create and Edit and Update won't work for 3rd laryer objects from Nested form on 1st layer in Rails 4.2
我正在使用 Rails 4.2 制作嵌套表格。我在对第 3 层对象 Answer 进行创建、编辑和更新操作时遇到问题。我在下面总结了信息。如果您知道我做错了什么或没有做,请告诉我。
范围:
- 用户可以创建调查和问答。
- 用户可以edit/update调查和问答。
- 用户可以删除调查和问答
问题:
我已经在 Survey > Questions > Answers 和 setup 'accepts_nested_attributes_for' 之间设置了嵌套的 has_many 关联,并在许可参数中添加了模型的属性。并制作了包含所有模型字段的调查表。它可以很好地创建带有问题的调查,从一个表单提交一个,并且这两个模型的属性也出现在 Show 操作中。但答案不会被保存,并且答案来自不会出现在编辑表单中。
代码:
型号
Survey.rb
class Survey < ActiveRecord::Base
has_many :questions, dependent: :destroy
accepts_nested_attributes_for :questions, allow_destroy: true
end
Question.rb
class Question < ActiveRecord::Base
belongs_to :survey
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, allow_destroy: true
end
Answer.rb
class Answer < ActiveRecord::Base
belongs_to :question
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
@questions = @survey.questions.build
@answers = @questions.answers.build
#@survey.questions.build
#@questions.answers.build
end
# GET /surveys/1/edit
def edit
# @questions = @survey.questions.update(survey_params) #This will get ActionController::ParameterMissing in SurveysController#edit
# @answers = @questions.answers.update(survey_params) #This will get ActionController::ParameterMissing in SurveysController#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, :description)
params.require(:survey).permit(:name, :description, questions_attributes: [:id, :name, :description, :_destroy])
# params.require(:survey).permit(:name, :description, questions_attributes: [:id, :name, :description, :_destroy, answers_attributes: [:id, :content, :_destroy]]) #I don't see any change from addin ansewrs attributes here
end
end
Questions_controller.rb
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
# GET /questions
# GET /questions.json
def index
@questions = Question.all
end
# GET /questions/1
# GET /questions/1.json
def show
end
# GET /questions/new
def new
@question = Question.new
@question.answers.build
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
@question = Question.new(question_params)
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
end
# DELETE /questions/1
# DELETE /questions/1.json
def destroy
@question.destroy
respond_to do |format|
format.html { redirect_to questions_url, notice: 'Question was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
@question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:name, :description, :survey_id, :_destroy, answers_attributes: [:id, :content, :_destroy])
end
end
Answers_controller.rb
class AnswersController < ApplicationController
before_action :set_answer, only: [:show, :edit, :update, :destroy]
# GET /answers
# GET /answers.json
def index
@answers = Answer.all
end
# GET /answers/1
# GET /answers/1.json
def show
end
# GET /answers/new
def new
@answer = Answer.new
end
# GET /answers/1/edit
def edit
end
# POST /answers
# POST /answers.json
def create
@answer = Answer.new(answer_params)
respond_to do |format|
if @answer.save
format.html { redirect_to @answer, notice: 'Answer was successfully created.' }
format.json { render :show, status: :created, location: @answer }
else
format.html { render :new }
format.json { render json: @answer.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /answers/1
# PATCH/PUT /answers/1.json
def update
respond_to do |format|
if @answer.update(answer_params)
format.html { redirect_to @answer, notice: 'Answer was successfully updated.' }
format.json { render :show, status: :ok, location: @answer }
else
format.html { render :edit }
format.json { render json: @answer.errors, status: :unprocessable_entity }
end
end
end
# DELETE /answers/1
# DELETE /answers/1.json
def destroy
@answer.destroy
respond_to do |format|
format.html { redirect_to answers_url, notice: 'Answer was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_answer
@answer = Answer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def answer_params
params.require(:answer).permit(:content, :question_id)
end
end
数据库
schema.rb
ActiveRecord::Schema.define(version: 20160602204457) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "answers", force: :cascade do |t|
t.string "content"
t.integer "question_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "answers", ["question_id", "created_at"], name: "index_answers_on_question_id_and_created_at", using: :btree
add_index "answers", ["question_id"], name: "index_answers_on_question_id", using: :btree
create_table "questions", force: :cascade do |t|
t.string "name"
t.string "description"
t.integer "survey_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "questions", ["survey_id", "created_at"], name: "index_questions_on_survey_id_and_created_at", using: :btree
add_index "questions", ["survey_id"], name: "index_questions_on_survey_id", using: :btree
create_table "surveys", force: :cascade do |t|
t.string "name"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "answers", "questions"
add_foreign_key "questions", "surveys"
end
观看次数
app/views/surveys/new.html.erb
<h1>New Survey</h1>
<%= render 'form' %>
<%= link_to 'Back', surveys_path %>
app/views/surveys/new.html.erb
<h1>Editing Survey</h1>
<%= render 'form' %>
<%= link_to 'Show', @survey %> |
<%= link_to 'Back', surveys_path %>
app/views/surveys/_form.html.erb
<%= form_for(@survey) do |f| %>
<%#= form_for(setup_survey(@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>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<%= f.fields_for :questions do |ff| %>
<%= render 'question_fields', ff: ff %>
<% end %>
<%= link_to_add_fields "Add Question", f, :questions %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
app/views/surveys/_question_fields.html.erb
<fieldset>
<div class="field">
<%= ff.label :name, "Question Name" %><br>
<%= ff.text_field :name %><br>
</div>
<div class="field">
<%= ff.label :description, "Question Description" %><br>
<%= ff.text_field :description %>
</div>
<div class="field">
<%= ff.check_box :_destroy %>
<%= ff.label :_destroy, "Remove Question" %>
</div>
<%= ff.fields_for :answers do |fff| %>
<%= render 'answer_fields', fff: fff %>
<% end %>
</fieldset>
app/views/surveys/_answer_fields.html.erb
<fieldset>
<div class="field">
<%= fff.label :content, "Answer" %>
<%= fff.text_field :content %>
</div>
<div class="field">
<%= fff.check_box :_destroy %>
<%= fff.label :_destroy, "Remove Answer" %>
</div>
</fieldset>
app/views/surveys/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= @survey.name %>
</p>
<p>
<strong>Description:</strong>
<%= @survey.description %>
</p>
<ul>
<% @survey.questions.each do |question| %>
<li>
<%= question.name %><br>
<%= question.description %>
<% question.answers.each do |answer| %>
<%= answer.content %>
<% end %>
</li>
<% end %>
</ul>
<%= link_to 'Edit', edit_survey_path(@survey) %> |
<%= link_to 'Back', surveys_path %>
谢谢!
您应该将 survey_params
中的 answers_attributes
列入白名单。像下面这样更改它应该可以让你继续。
def survey_params
params.require(:survey).permit(:name, :description, questions_attributes: [:id, :name, :description, :_destroy, answers_attributes: [:id, :content, :_destroy]])
end
我正在使用 Rails 4.2 制作嵌套表格。我在对第 3 层对象 Answer 进行创建、编辑和更新操作时遇到问题。我在下面总结了信息。如果您知道我做错了什么或没有做,请告诉我。
范围:
- 用户可以创建调查和问答。
- 用户可以edit/update调查和问答。
- 用户可以删除调查和问答
问题: 我已经在 Survey > Questions > Answers 和 setup 'accepts_nested_attributes_for' 之间设置了嵌套的 has_many 关联,并在许可参数中添加了模型的属性。并制作了包含所有模型字段的调查表。它可以很好地创建带有问题的调查,从一个表单提交一个,并且这两个模型的属性也出现在 Show 操作中。但答案不会被保存,并且答案来自不会出现在编辑表单中。
代码:
型号
Survey.rb
class Survey < ActiveRecord::Base
has_many :questions, dependent: :destroy
accepts_nested_attributes_for :questions, allow_destroy: true
end
Question.rb
class Question < ActiveRecord::Base
belongs_to :survey
has_many :answers, dependent: :destroy
accepts_nested_attributes_for :answers, allow_destroy: true
end
Answer.rb
class Answer < ActiveRecord::Base
belongs_to :question
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
@questions = @survey.questions.build
@answers = @questions.answers.build
#@survey.questions.build
#@questions.answers.build
end
# GET /surveys/1/edit
def edit
# @questions = @survey.questions.update(survey_params) #This will get ActionController::ParameterMissing in SurveysController#edit
# @answers = @questions.answers.update(survey_params) #This will get ActionController::ParameterMissing in SurveysController#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, :description)
params.require(:survey).permit(:name, :description, questions_attributes: [:id, :name, :description, :_destroy])
# params.require(:survey).permit(:name, :description, questions_attributes: [:id, :name, :description, :_destroy, answers_attributes: [:id, :content, :_destroy]]) #I don't see any change from addin ansewrs attributes here
end
end
Questions_controller.rb
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
# GET /questions
# GET /questions.json
def index
@questions = Question.all
end
# GET /questions/1
# GET /questions/1.json
def show
end
# GET /questions/new
def new
@question = Question.new
@question.answers.build
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
@question = Question.new(question_params)
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
end
# DELETE /questions/1
# DELETE /questions/1.json
def destroy
@question.destroy
respond_to do |format|
format.html { redirect_to questions_url, notice: 'Question was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_question
@question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:name, :description, :survey_id, :_destroy, answers_attributes: [:id, :content, :_destroy])
end
end
Answers_controller.rb
class AnswersController < ApplicationController
before_action :set_answer, only: [:show, :edit, :update, :destroy]
# GET /answers
# GET /answers.json
def index
@answers = Answer.all
end
# GET /answers/1
# GET /answers/1.json
def show
end
# GET /answers/new
def new
@answer = Answer.new
end
# GET /answers/1/edit
def edit
end
# POST /answers
# POST /answers.json
def create
@answer = Answer.new(answer_params)
respond_to do |format|
if @answer.save
format.html { redirect_to @answer, notice: 'Answer was successfully created.' }
format.json { render :show, status: :created, location: @answer }
else
format.html { render :new }
format.json { render json: @answer.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /answers/1
# PATCH/PUT /answers/1.json
def update
respond_to do |format|
if @answer.update(answer_params)
format.html { redirect_to @answer, notice: 'Answer was successfully updated.' }
format.json { render :show, status: :ok, location: @answer }
else
format.html { render :edit }
format.json { render json: @answer.errors, status: :unprocessable_entity }
end
end
end
# DELETE /answers/1
# DELETE /answers/1.json
def destroy
@answer.destroy
respond_to do |format|
format.html { redirect_to answers_url, notice: 'Answer was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_answer
@answer = Answer.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def answer_params
params.require(:answer).permit(:content, :question_id)
end
end
数据库
schema.rb
ActiveRecord::Schema.define(version: 20160602204457) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "answers", force: :cascade do |t|
t.string "content"
t.integer "question_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "answers", ["question_id", "created_at"], name: "index_answers_on_question_id_and_created_at", using: :btree
add_index "answers", ["question_id"], name: "index_answers_on_question_id", using: :btree
create_table "questions", force: :cascade do |t|
t.string "name"
t.string "description"
t.integer "survey_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "questions", ["survey_id", "created_at"], name: "index_questions_on_survey_id_and_created_at", using: :btree
add_index "questions", ["survey_id"], name: "index_questions_on_survey_id", using: :btree
create_table "surveys", force: :cascade do |t|
t.string "name"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "answers", "questions"
add_foreign_key "questions", "surveys"
end
观看次数
app/views/surveys/new.html.erb
<h1>New Survey</h1>
<%= render 'form' %>
<%= link_to 'Back', surveys_path %>
app/views/surveys/new.html.erb
<h1>Editing Survey</h1>
<%= render 'form' %>
<%= link_to 'Show', @survey %> |
<%= link_to 'Back', surveys_path %>
app/views/surveys/_form.html.erb
<%= form_for(@survey) do |f| %>
<%#= form_for(setup_survey(@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>
<div class="field">
<%= f.label :description %><br>
<%= f.text_field :description %>
</div>
<%= f.fields_for :questions do |ff| %>
<%= render 'question_fields', ff: ff %>
<% end %>
<%= link_to_add_fields "Add Question", f, :questions %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
app/views/surveys/_question_fields.html.erb
<fieldset>
<div class="field">
<%= ff.label :name, "Question Name" %><br>
<%= ff.text_field :name %><br>
</div>
<div class="field">
<%= ff.label :description, "Question Description" %><br>
<%= ff.text_field :description %>
</div>
<div class="field">
<%= ff.check_box :_destroy %>
<%= ff.label :_destroy, "Remove Question" %>
</div>
<%= ff.fields_for :answers do |fff| %>
<%= render 'answer_fields', fff: fff %>
<% end %>
</fieldset>
app/views/surveys/_answer_fields.html.erb
<fieldset>
<div class="field">
<%= fff.label :content, "Answer" %>
<%= fff.text_field :content %>
</div>
<div class="field">
<%= fff.check_box :_destroy %>
<%= fff.label :_destroy, "Remove Answer" %>
</div>
</fieldset>
app/views/surveys/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Name:</strong>
<%= @survey.name %>
</p>
<p>
<strong>Description:</strong>
<%= @survey.description %>
</p>
<ul>
<% @survey.questions.each do |question| %>
<li>
<%= question.name %><br>
<%= question.description %>
<% question.answers.each do |answer| %>
<%= answer.content %>
<% end %>
</li>
<% end %>
</ul>
<%= link_to 'Edit', edit_survey_path(@survey) %> |
<%= link_to 'Back', surveys_path %>
谢谢!
您应该将 survey_params
中的 answers_attributes
列入白名单。像下面这样更改它应该可以让你继续。
def survey_params
params.require(:survey).permit(:name, :description, questions_attributes: [:id, :name, :description, :_destroy, answers_attributes: [:id, :content, :_destroy]])
end