accepting_attributes_for - 为什么我的表单从我的嵌套模型中删除实例?

问题描述:

我有...accepting_attributes_for - 为什么我的表单从我的嵌套模型中删除实例?

/app/models/survey.rb

class Survey < ActiveRecord::Base 

    has_many :results 
    belongs_to :competitor 
    after_commit :create_matching_results 
    attr_accessible :results_attributes 
    accepts_nested_attributes_for :results 
    after_commit :create_matching_results 
    def create_matching_results 
    unless self.destroyed? 
     self.fields.each do |field| 
     result = survey.results.find_or_create_by_survey_id_and_field_id(self.id, field_id) 
     result.update_attributes :competitor_id => competitor.id 
     end 
    end 
    end 
end 

/app/models/result.rb

class Result < ActiveRecord::Base 
    attr_accessible :field_id, :survey_id, :competitor_id, :value, :selected, :name 
    belongs_to :survey 
end 

/应用/controllers/surveys_controller.rb

class SurveysController < ApplicationController 
    def edit 
    @competitor = Competitor.find(params[:competitor_id]) 
    @survey = @competitor.surveys.find(params[:id]) 
    end 
    def update 
    @competitor = Competitor.find(params[:competitor_id]) 
    @survey = @competitor.surveys.find(params[:id]) 
    @result_ids = params[:survey]["result_ids"] 
    @survey.results.each do |result| 
     result.update_attributes :selected => true if result.id == @result_ids.to_i 
     result.update_attributes :selected => false unless result.id == @result_ids.to_i 
    end 
    flash[:notice] = "Survey was successfully updated. (#{undo_link(@survey)}.)" if @survey.update_attributes(params[:survey]) 
    respond_with(@competitor, @survey) 
    end 
end 

/app/views/surveys/_form.html.haml

= simple_form_for [@competitor, @survey] do |f| 
    = f.collection_radio_buttons :result_ids, @survey.results, :id, :name 
    = f.button :submit, :id => 'submit_survey' 

现在让我们假设@ survey.results.count == 2.然后,我会得到一些可爱的HTML像这在我的形式:

<form accept-charset="UTF-8" action="/competitors/13/surveys/80" class="simple_form edit_survey" id="edit_survey_80" method="post" novalidate="novalidate"> 
    <input id="survey_result_ids_673" name="survey[result_ids]" type="radio" value="673" /> 
    <label class="collection_radio_buttons" for="survey_result_ids_673">one</label> 
    <input id="survey_result_ids_672" name="survey[result_ids]" type="radio" value="672" /> 
    <label class="collection_radio_buttons" for="survey_result_ids_672">two</label> 
    <input class="btn" id="submit_survey" name="commit" type="submit" value="Update Survey" /> 
</form> 

到目前为止,这么好。

当我选择这两个单选按钮中的一个,我的PARAMS是这样的:

{"utf8"=>"✓", 
"_method"=>"put", 
"authenticity_token"=>"etc...", 
"survey"=>{"result_ids"=>"672"}, 
"commit"=>"Update Survey", 
"action"=>"update", 
"controller"=>"surveys", 
"competitor_id"=>"13", 
"id"=>"80"} 

因此,我预计的Result.find(672)selected值设置为true和其他的selected值结果设置为false。相反,我发现其他结果完全被删除。这是怎么回事?我该如何解决它?

UPDATE

例如,我开始@survey.results.count == 4,具有results.selected == false。然后,我做了在Rspec的以下内容:

visit edit_competitor_survey_path(@competitor, @survey) 
    choose "Standard practice" 
    @dummy = @survey.results.map{|result| [result.name, " - ", result.selected].join} 
    click_on "submit_survey" 
    @survey.results.reload.map{|result| [result.name, " - ", result.selected].join}.should == @dummy 

然后我得到:

Failure/Error: @survey.results.reload.map{|result| [result.name, " ", result.selected].join}.should == @dummy 
     expected: ["Best practice - false", "Good practice - false", "Standard practice - false", "Bad practice - false"] 
      got: ["Standard practice - true"] (using ==) 

(不,我在“之前”和“之后”值等于期待这招只是一个方便在Rspec测试失败消息中显示这两个值的方法)。

答案是删除accepts_nested_attributes_for,因为我已经直接设置了结果值。

class Survey < ActiveRecord::Base 
    belongs_to :competitor 
    attr_accessible :selection 
    attr_accessor :selection 
    has_many :results 
    belongs_to :question 
end 

class SurveysController < ApplicationController 
    def update 
    @competitor = Competitor.find(params[:competitor_id]) 
    @survey = @competitor.surveys.find(params[:id]) 
    @result_ids = params[:survey]["selection"] 
    @survey.results.each do |result| 
     result.update_attributes :selected => true if result.id == @result_ids.to_i 
     result.update_attributes :selected => false unless result.id == @result_ids.to_i 
    end 
    flash[:notice] = "Survey was successfully updated. (#{undo_link(@survey)}.)" if @survey.update_attributes(params[:survey]) 
    respond_with(@competitor, @survey) 
    end 
end 

= simple_form_for [@competitor, @survey] do |f| 
    = f.collection_radio_buttons :selection, @survey.results, :id, :name 
    = f.button :submit, :id => 'submit_survey'