问题 Rails 4嵌套属性不保存


我似乎无法获得嵌套属性来保存到数据库。我正在使用Rails 4。

这是我的模特:

class Answer < ActiveRecord::Base
  belongs_to :question
end


class Question < ActiveRecord::Base
  has_many :answers
  belongs_to :survey
  accepts_nested_attributes_for :answers, allow_destroy: true
end

class Survey < ActiveRecord::Base
  has_many :questions
  validates_presence_of :name
  accepts_nested_attributes_for :questions
end

这是控制器:

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 action: 'show', status: :created, location: @survey }
    else
      format.html { render action: 'new' }
      format.json { render json: @survey.errors, status: :unprocessable_entity }
    end
  end
end

def survey_params
  params.require(:survey).permit(:name, questions_attributes:[:content, :id, :survey_id, 
    answers_attributes:[:content, :id, :questions_id]
    ])
end

最后,这是表单本身。我尝试过同时使用f.fields_for和fields_for

<%= 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 |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>

  <%= f.fields_for :question do |builder| %>
     <%= builder.label :content %>
     <%= builder.text_area :content %>

       <%= f.fields_for :answer do |builder| %>
         <%= builder.label :content, "Answer" %>
         <%= builder.text_field :content %>
       <% end %>

  <% end %>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

该调查可以很好地保存数据库,不会提出问题和答案。我看过我能找到的每一种资源,看起来我正确地做到了这一点,所以它真的让我发疯了。

这个例子只是一个快速的脚手架,所以我有一些代码要粘贴,但我似乎无法让它在其他任何地方工作。

编辑: 把我的新动作改成这样的事情

def new
  @survey = Survey.new
  @survey.questions.build
end

成功了!

请参阅解决方案以获得解决方案

这是我正在使用的新表单,仍然只保存调查名称

  <%= f.fields_for :question do |question_builder| %>
  <%= 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 |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>

  <%= f.fields_for :question do |question_builder| %>
   <%= question_builder.label :content %>
   <%= question_builder.text_area :content %>

   <%= question_builder.fields_for :answer do |answer_builder| %> 
       <%= answer_builder.label :content, "Answer" %>
       <%= answer_builder.text_field :content %>
   <% end %>

<% end %>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

11767
2018-02-11 19:47


起源

你尝试过使用过吗? build 为你创造空洞的关系 new 控制器中的动作? - rlecaro2
@ rlecaro2我尝试将我的新动作改为:`def new @survey = Survey.new @ survey.questions.build end`它仍然无效 - Michael


答案:


看起来你正在使用错误的表单构建器对象。将问题部分更改为以下内容:

<%= f.fields_for :question do |question_builder| %>
   <%= question_builder.label :content %>
   <%= question_builder.text_area :content %>

   <%= question_builder.fields_for :answer do |answer_builder| %> 
       <%= answer_builder.label :content, "Answer" %>
       <%= answer_builder.text_field :content %>
   <% end %>

<% end %>

原来你用的是 f 行中的表单构建器 f.fields_for :answers...但是考虑到你的型号代码,因为它是一个 Question 那 accepts_nested_attributes_for 一个 Answer,我们只需将表单生成器对象替换为用于表单的表单生成器对象 question 部分。

注意:为清楚起见,我更改了构建器对象的名称。

更新

为了建立这样一个深层嵌套的关系,你将不得不循环你的“建立”关联(questions 在这种情况下),并调用 build 再次对它 has_many 协会。所以关闭gabrielhilal的答案,你会这样做:

def new
  @survey = Survey.new
  @survey.questions.build
  @survey.questions.each do |question|
      question.answers.build
  end
end

注意 在您的情况下,因为您只是明确地创建了一个问题,所以您可以在技术上改为(而不是循环):

@survey.questions.first.answers.build

免责声明: 如果有一个更干净,更多的Rails-y,这样做的方式,我很遗憾没有意识到它。


7
2018-02-11 20:19



哇,不知道我是怎么错过的。但是,在修复它之后,我仍然遇到同样的问题。这令人费解。 - Michael
@Michael gabrielhilal的答案对你有帮助吗?我忘记了 .build 部分。这可能会有所不同。 - Paul Richter
是的,它确实!修复表单并添加@ survey.questions.build可以保存问题。我只需要弄清楚如何构建答案。我尝试将此添加到我的模型中: has_many :answers, through: :questions 这对我的控制器 def new @survey = Survey.new @survey.questions.build @survey.answers.build end 但是答案字段没有显示出来。 - Michael
@Michael查看我的更新,如果有效,请告诉我。 - Paul Richter
是的,有效!我不知道为什么我没想到这一点。非常感谢! - Michael


在你的控制器中你有 questions_id

def survey_params
  params.require(:survey).permit(:name, 
    questions_attributes: [
      :content, :id, :survey_id, 
      answers_attributes: [:content, :id, :questions_id]
    ]
  )
end

这是一个错字吗?也尝试设置 action_on_unpermitted_parameters 至 :raise 在你身上 development.rb 看看你的遗失中是否有任何属性 survey_params 方法。

# In case of unpermitted parameters in the controller raise error.
config.action_controller.action_on_unpermitted_parameters = :raise

4
2018-02-11 20:22



这是一个错字。我尝试将该设置添加到我的development.rb中,并且在保存调查时我没有提出错误。 - Michael
在看到这篇文章之前,我和我自己的类似问题花了两个半小时。我需要做的就是把我的 answers_attributes[] 我的内心 questions_attributes[]。先生,你很棒。 - Darkstarone


你必须改变你的 new 要包括的行动 @survey.questions.build

def new
  @survey = Survey.new
  @survey.questions.build
end

但你的形式也是错误的。改变 question 至 questions

 <%= f.fields_for :questions do |builder| %> #questions
   <%= builder.label :content %>
   <%= builder.text_area :content %>

你必须为答案做同样的事情。


3
2018-02-11 20:19



这加上上面的东西的组合我得到了保存的问题!现在如何获得构建的答案?我尝试将调查关系改为has_many:答案,通过:问题并添加@ survey.answers.build,但表单不显示答案。 - Michael