3

我遇到了一个相当奇怪的错误。除了在现有记录上验证失败时,我有一个嵌套表单,可以按预期工作。在现有记录上验证失败时,重新呈现的编辑视图会为无效记录包含两次字段。第一组字段根据对象当前存储的方式填写。第二组字段填写了刚刚提交并发现无效的信息。Rails fields_for验证后现有记录的重复表单

我有一个基本的嵌套形式,父母(ShiftPeriod)has_many孩子(Shifts)和每个孩子belongs_to父母。对于Shifts,ShiftPeriod accepted_nested_attributes,allow_destroy设置为true。我使用的是nested_form宝石,但我用一个普通的form_for具有相同的结果

的形式ShiftPeriod也试过(我删除尽可能设法保持简单,直到我想出解决办法):

<%= nested_form_for @shift_period do |f| %> 
    <%= f.fields_for :shifts %> 
    <%= f.link_to_add "Add shift", :shifts %> 
    <%= f.submit %> 
<% end %> 

的局部与转移的字段:

<%= f.select :member_id, options_for_select(Member.crew_members.order('last_name').collect{|member| ["#{member.last_name}, #{member.first_name}", member.id]}, :selected => Member.where(:bars_num == 1).first.id) %> 
<%= f.collection_select :start_time, @time_range, :dup, :hour, :selected => Time.parse(f.object.start_time.to_s) || @shift_period.start_time %> 
<%= f.collection_select :end_time, @time_range, :dup, :hour, :selected => f.object.new_record? ? @time_range.last : Time.parse(f.object.end_time.to_s) %> 
<%= f.select :repeat_month, options_for_select([['Never', false], ['Monthly', true]]) %> 
<%= f.select :repeat, options_for_select([['Never', 0], ['Every Other Week', 1], ['Every Week', 2]]) %> 
<%= f.link_to_remove "Remove" %> 

移位对象的相关部分:

class Shift < ActiveRecord::Base 
    include Coverage::SetOperations 

    belongs_to :member 
    belongs_to :shift_period 

    delegate :date, :to => :shift_period 
    delegate :daynight, :to => :shift_period 

    after_save :update_shift_period_open_slots 
    after_destroy :update_shift_period_open_slots 

    validates_presence_of :member, :start_time, :end_time, :shift_period 

的ShiftPeriod对象的相关部分:

class ShiftPeriod < ActiveRecord::Base 
    has_many :shifts 
    has_many :open_slots, :dependent => :destroy 
    has_many :calls 
    after_create :update_open_slots 
    validates_presence_of :date 
    validates :date, :uniqueness => {:scope => :daynight} 

    accepts_nested_attributes_for :shifts, :reject_if => lambda {|a| a[:start_time].blank? || a[:end_time].blank? || a[:member_id].blank? || a[:repeat].blank? }, :allow_destroy => true 

控制器: as_many儿童(移动),并且每个孩子belongs_to的父。对于Shifts,ShiftPeriod accepted_nested_attributes,allow_destroy设置为true。我使用的是nested_form宝石,但我用一个普通的form_for同样的结果还试图

控制器:

def edit 
    @shift_period = ShiftPeriod.find(params[:id]) 
    set_time_range 
end 

def set_time_range 
    @time_range = @shift_period.daynight ? (6..18).to_a : (18..23).to_a + (0..6).to_a 
    @time_range.collect!{|val| @shift_period.start_time - @shift_period.start_time.hour.hours + val.hours } 
end 

def update 
    @shift_period = ShiftPeriod.find(params[:id]) 
    respond_to do |format| 
    if @shift_period.update_attributes(params[:shift_period]) 
     format.html { redirect_to(schedule_path(:date => @shift_period.date, :notice => 'Shift period was successfully updated')) } 
     format.xml { head :ok } 
    else 
     set_time_range 
     format.html { render :action => "edit" } 
     format.xml { render :xml => @shift_period.errors, :status => :unprocessable_entity } 
    end 
    end 
end 

为ShiftPeriod的形式(我删除尽可能要尽量保持它简单直到我算出这个):

<%= nested_form_for @shift_period do |f| %> 
    <%= f.fields_for :shifts %> 
    <%= f.link_to_add "Add shift", :shifts %> 
    <%= f.submit %> 
<% end %> 

局部与字段偏移:

<%= f.select :member_id, options_for_select(Member.crew_members.order('last_name').collect{|member| ["#{member.last_name}, #{member.first_name}", member.id]}, :selected => Member.where(:bars_num == 1).first.id) %> 
<%= f.collection_select :start_time, @time_range, :dup, :hour, :selected => Time.parse(f.object.start_time.to_s) || @shift_period.start_time %> 
<%= f.collection_select :end_time, @time_range, :dup, :hour, :selected => f.object.new_record? ? @time_range.last : Time.parse(f.object.end_time.to_s) %> 
<%= f.select :repeat_month, options_for_select([['Never', false], ['Monthly', true]]) %> 
<%= f.select :repeat, options_for_select([['Never', 0], ['Every Other Week', 1], ['Every Week', 2]]) %> 
<%= f.link_to_remove "Remove" %> 

移位对象的相关部分:

class Shift < ActiveRecord::Base 
    include Coverage::SetOperations 

    belongs_to :member 
    belongs_to :shift_period 

    delegate :date, :to => :shift_period 
    delegate :daynight, :to => :shift_period 

    after_save :update_shift_period_open_slots 
    after_destroy :update_shift_period_open_slots 

    validates_presence_of :member, :start_time, :end_time, :shift_period 

的ShiftPeriod对象的相关部分:

class ShiftPeriod < ActiveRecord::Base 
    has_many :shifts 
    has_many :open_slots, :dependent => :destroy 
    has_many :calls 
    after_create :update_open_slots 
    validates_presence_of :date 
    validates :date, :uniqueness => {:scope => :daynight} 

    accepts_nested_attributes_for :shifts, :reject_if => lambda {|a| a[:start_time].blank? || a[:end_time].blank? || a[:member_id].blank? || a[:repeat].blank? }, :allow_destroy => true 

控制器:

def edit 
    @shift_period = ShiftPeriod.find(params[:id]) 
    set_time_range 
end 

def set_time_range 
    @time_range = @shift_period.daynight ? (6..18).to_a : (18..23).to_a + (0..6).to_a 
    @time_range.collect!{|val| @shift_period.start_time - @shift_period.start_time.hour.hours + val.hours } 
end 

def update 
    @shift_period = ShiftPeriod.find(params[:id]) 
    respond_to do |format| 
    if @shift_period.update_attributes(params[:shift_period]) 
     format.html { redirect_to(schedule_path(:date => @shift_period.date, :notice => 'Shift period was successfully updated')) } 
     format.xml { head :ok } 
    else 
     set_time_range 
     format.html { render :action => "edit" } 
     format.xml { render :xml => @shift_period.errors, :status => :unprocessable_entity } 
    end 
    end 
end 
+0

多一点摆弄,我发现正在显示重复的形式,因为在我的父类的子关联的每个录制两个Ruby对象(@ shift_period.shifts)。换句话说,在与同一个id关联中有多个shift对象。例如,如果我显示@ shift_period.shifts。在有两个现有班次的班次期间,最初为2,在尝试提交无效班次后为4,编辑视图再次呈现。不知道为什么......任何人有任何想法? – 2011-06-17 01:35:04

+0

我现在正在使用hack来解决这个问题(再次渲染编辑之前,从关联数组中删除重复的对象),但为什么fields_for仅仅因为验证失败而将多个对象添加到每个记录的关联?为什么只有在现有记录验证失败而不是新记录时才会出现这种情况? – 2011-06-17 01:48:24

+0

该死的,即使在4年后[同样的问题仍然存在!](https://github.com/ryanb/nested_form/issues/346)。但是,也许你找到了问题的根源? – 2015-04-29 22:59:59

回答

1

这里是我使用的黑客现在要解决这个问题,更好的想法将不胜感激。

def update 
    @shift_period = ShiftPeriod.find(params[:id]) 
    if @shift_period.update_attributes(params[:shift_period]) 
    redirect_to(schedule_path(:date => @shift_period.date, :notice => 'Shift period was successfully updated')) 
    else 
    set_time_range 

    new_records = [] 
    @shift_period.shifts.each{|shift| if shift.new_record? then new_records << shift end} 
    @shift_period.shifts.slice!(0,@shift_period.shifts.length/2) 
    @shift_period.shifts += new_records 
    render :action => "edit" 
    end