在模型中接受嵌套属性,该模型包含与其自身无关的其他模型

Accepting nested attributes in within a model, that contains other models not associated to itself

好的,我有一个小问题,我不是。我知道我即将解决这个问题,但我需要一些帮助。好吧,基本上我正在创建的是一个网站,允许用户提交调查,然后让人们回答这些调查。所以我创建了一个调查模型,它使用问题,而这些问题使用答案。当用户创建调查时,他只创建调查和问题,然后通过另一个称为结果的模型创建答案。我遇到的麻烦是通过结果表将这些答案作为问题的一部分提交。所以这是我的结果控制器:

class ResultsController < ApplicationController
  before_action :set_result, only: [:show]

  def show
    @survey = Survey.find(params[:survey_id])
  end

  def new
    @survey = Survey.find(params[:survey_id])
    @survey.questions.all.each do |question|
      question.build_answer
    end 
    @result = @survey.results.build
  end

  def create
    @survey = Survey.find(params[:survey_id])
    @result = @survey.results.build

    respond_to do |format|
      if @result.save
        format.html { redirect_to survey_result_path(@result), notice: 'Survey was successfully answered.' }
      else
        format.html { render :new }
      end
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_result
      @result = Result.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def result_params
      params.require(:result).permit(:survey_id)
    end
end

所以在我的表单中,我试图将答案作为问题的一部分而不是结果来提交。

外观如下:

<%= form_for([@survey, @result]) do |f| %>
  <% if @result.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@result.errors.count, "error") %> prohibited this result from being saved:</h2>

      <ul>
      <% @result.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  <% for question in @survey.questions  %>   
    <div class="field">
      <label><%= question.question_content %></label>
        <%= fields_for :answer, question.build_answer do |builder| %>
          <%= builder.text_field :answer_content, placeholder: "Answer"%>
        <% end %>
    </div>
  <% end %>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

无论如何,这是相关部分:

<% for question in @survey.questions  %>   
        <div class="field">
          <label><%= question.question_content %></label>
            <%= fields_for :answer, question.build_answer do |builder| %>
              <%= builder.text_field :answer_content, placeholder: "Answer"%>
            <% end %>
         </div>

我还应该提一下,问题和答案没有控制器,它们只是模型,我不需要它们的任何视图或控制器,根本没有任何理由拥有这些组件。

我不知道答案和问题与结果没有任何关系是否是一个问题。如果改变它更好,那么我会这样做,但到目前为止,这是我遇到的唯一问题。如果有人能帮我解决这个问题,我将不胜感激,这是一个长期困难项目的最后一步。

我相信你的话,你已经尝试了@max 的建议,看看这已经完成了 - 我同意@max 的观点,看看人们如何解决它会给你一个比什么更好的答案我有给你。但是,如果您已经尝试过,那么也许这会有所帮助。

这不是您问题的答案,但它可能是您问题的解决方案。我也同意 @max 的第一条评论 - 看起来你试图对那个控制器做太多事情。如果是我,我会进行一些重构并查看您的整体设计,而不是解决这个特定问题。

这是我的建议。 (免责声明:我没有重新创建您的项目来对其进行测试,也没有提供足够的细节使其成为逐步说明。)这只是解决问题的另一种方法的一个想法。我认为通过简化每个控制器必须做的事情会让你的问题消失。

建议

  • 分开你的控制器 - SurveysControllerResultsController 就像@max 建议的那样
  • Result class 与 Survey class 相关联(可能是调查 has_many :results,如果一项调查可以完成多次)
  • 从路由的角度来看,使用 nested resources 将结果作为调查的子项(因此您的 url 可能看起来像 http://yoursite.com/survey/12/result/2 查看调查的第二组答案# 12)
  • 从调查视图中,link 作为您的 "respond to the survey" link 到您的新结果路线。换句话说,通过创建 belongs_to 相关调查的新结果来回答调查。这个新结果将由与您用于创建和管理调查的控制器不同的控制器创建、编辑和保存
  • 关键部分:从结果模型中,当您创建一个新结果时,使用回调为关联调查中的每个问题创建一个答案(但保留文本现在的答案是空的)[见下面的 result.rb 片段]
  • 在视图中,允许用户为每个空答案提供文本[参见下面的 views/results/edit。html.erb 片段]
  • 显示结果时,将调查问题 id 与结果答案匹配 ID

在result.rb

after_initialize :create_answers

def create_answers
  return unless self.new_record? # don't create them if it isn't a new record
  self.survey.questions.each_with_index do |q,i|
    self.answers.create(question_index: i)
  end
end

在views/results/edit.html.erb

<% @result.answers.each_with_index do |a,i| %>
  <!-- label the answer with: -->
  <%= @result.survey.questions[i] %>
  <!-- render the form field for: --> 
  <%= a.text %>
<% end %>

来自 views/results/show.html.erb 从 http://yoursite.com/survey/12/result/2

访问
<dl>
<% @result.survey.questions.each_with_index do |q,i| %>
  <dt class="question"><%= q.text %></dt>
  <dd class="answer"><%= @result.answers[i] %></dd>
<% end %>
</dl>

总结

这使您可以使用与保存结果时相同的基本控制器逻辑来创建调查。您让模型负责匹配问题和答案,然后控制器只需处理结果及其子答案,或调查及其子问题。

同样,这不是一个完整的解决方案,但希望有一些想法可以帮助您继续前进。

进一步改进

这还是有点丑 - @result.survey.questions[index] 不是很干净。如果是我,我会让一切正常,然后以某种方式将 @result.survey.questions[index] 的东西重构到结果模型中——可能是这样的: Result#question_answer_pairs 那个 returns 一个二维数组(但那仍然不是很干净)。或者,使用 ActiveRecord 将每个答案与相应的问题相关联,这样您就可以并排使用 answer.textanswer.question_text