我有一个相当简单的rails应用程序,可以处理数学测验。用户可以创建一个问题和一个答案的数学问题。他们还可以创建带有标题的考试模型与has_many_和_belong_to relationship联系在一起,因为每个测验可能有许多问题,每个问题可能属于许多测验。这种关系似乎很好,因为当我删除问题或考试时,相关的对象列表会更新。我现在的方法是,当你创建一个考试时,视图会给你一个复选框列表,在问题数据库中每个问题都有一个。用户单击复选框以查找他们希望在考试中出现的问题,无论选中哪个复选框,这些问题都会添加到考试中。我将显示更新的代码,因为这是我一直用来测试的视图。
这是景色:

  <h2>Available Problems:</h2>
  <% Problem.all.each do |prob| %>
    <%= f.fields_for "exam[problem_ids][]", prob do |builder| %>
      <p>
      <%= check_box_tag "exam[problem_ids][]", prob.id, @exam.problems.include?(prob) %>
      <%= prob.question %> = <%= prob.answer %> | <%= link_to "Edit", edit_problem_path(prob) %>
      </p>
    <% end %>
  <% end %>

我必须使用check_box_tag,因为如果我尝试使用builder.check_box,它将不会保存已选中的框。
我的控制器:
  def update
    @exam = Exam.find(params[:id])

    if @exam.update_attributes(params[:exam].permit(:title, :problem_ids))
      redirect_to @exam
    else
      render 'edit'
    end
  end

在视图中,我将所有复选框结果保存在problem_ids数组中。我知道这个数组被正确填充了,因为当我添加下面的代码时,它就工作了。
@exam.problems = []
params[:exam][:problem_ids].each {
  |prob_id|
  @exam.problems << Problem.find(prob_id)
}

显然,这是一种非常骇人的方法,因为我每次都手动构建问题列表,但我一辈子都搞不懂如何让这些复选框结果自动填充到update_attributes方法中有什么想法吗?
更新:
根据多诺万的以下建议,我在我的考试模式中实施了以下方法:
  def problem_ids=(some_problem_ids)
    @exam.problems.clear
    some_problem_ids.each {
      |prob_id|
      @exam.problems << Problem.find(prob_id)
    }
  end

据我所知,这应该是problem_ids的“setter”方法遗憾的是,当我在考试控制器中使用以下行时,问题列表仍然没有更新:
@exam.update_attributes(params[:exam].permit(:title, :problem_ids))

注意,我必须把.permit(:title, :problem_ids)位放进去,否则我会得到ForbiddenAttributesError

最佳答案

@exam.problems是一个对象列表,但是由于这种关系,在您的考试中还应该有一个problem_idssetter方法,所以

@exam.update_attributes(params[:exam])

应该做你想做的如果出于某种原因,您只需要更新问题ID,那么这就可以做到:
@exam.update_attribute(:problem_ids, params[:exam][:problem_ids])

注意:我省略了rails4 strong_参数,以使答案对于rails 3或rails4是通用的,确保您对您的版本使用了适当的方法。

10-06 10:33