在更新或保存时,如何一一验证轨道中的嵌套对象,而不作为作用域?

问题描述

我遇到了用于批量模型关系创建的Rails验证问题。

让我告诉你情况

我有2个模型:Job和Appointment,其中job has_many多个约会,并且约会属于该工作。两种模式都有accepts_nested_attributes_for :appointments/:job

一个页面,其中显示Job表单(simple_form_for @job),并且此表单具有用于约会的嵌套表单(simple_fields_for :appointments)。因此,还有一个控制器可以处理作业更新外观,认情况下为rails。

if @job.update(bulk_new_appointments_params)
  redirect_to <success_path>,notice: 'Appointments was successfully created.'
else
  render :bulk_new_appointments
end

这很好。可以成功创建工作的约会,而且看起来很棒。

但是有1个验证约会模型。此验证将命中数据库,并检查约会与另一个作​​业的约会(之前创建)的日期时间重叠。 例如。如果您对10/10/2020 2:00PM with 2h duration有1个约会,则不能在2:00PM4:00PM

之间创建约会

但是,如果您发送2个约会的日期时间与此类似,则为:

params: {
  job: {
    appointments_attributes: {
        1: {id:... datetime: '10/10/2020 4PM',duration: '2h' }
        2: {id:... datetime: '10/10/2020 5PM',duration: '1h' }
      }
  }
}

当这些参数到达@job.update(attributes)时,Rails首先检查每个项目的有效性,然后保存它们。但是正如我之前说的-我们已经进行了数据库级验证。因此,两个日期时间重叠的新约会是“有效的”,因为这两个约会都没有记录到数据库中,并且重叠的检查返回有效。

因此,现在提出一个更精确的问题: 如何更改Rails的认记录更新策略?

发件人:

全部验证,然后全部保存

收件人:

验证一个然后保存一个(对所有集合重复一次)

解决方法

我有一个类似的问题,但是我的方法是验证并拒绝(如果有人与当前工作重叠)。为此,我需要在“约会”中使用一种validate方法来检查职位任命。本质上...

class Appointmment
  validate :no_overlap_in_this_job

  def no_overlap_in_this_job
     return if _destroy
     job.appointments.each do |appointment|
       next if appointment == self
       if start_time < appointment.end_time && end_time > appointment.start_time
         errors.add(:base,'this appointment overlaps another in the job')
         break
       end
     end
  end  

之所以可行,是因为验证可以访问未保存的约会和未保存的约会的工作。您仍将需要当前的验证,该验证将检查此作业中的约会是否与其他作业重叠。