* _attributes =()无法验证嵌套属性

时间:2011-05-20 14:51:07

标签: ruby-on-rails ruby-on-rails-3 validation

原标题:更新时的before_validation - 未正确处理错误

我正在试图弄清楚如何处理嵌套对象的验证,特别是在更新时。

我的父类处理嵌套属性。

meeting.rb

has_many :proposed_times, :dependent => :destroy, :inverse_of => :meeting
validates_associated :proposed_times
accepts_nested_attributes_for :proposed_times
...
def proposed_times_attributes=(attributes)
  attributes.each do |key,value|
    value[:timezone] = timezone
    if value[:id]
      p = ProposedTime.find(value[:id])
      value.delete(:id)
      p.update_attributes(value)
    else
      self.proposed_times << ProposedTime.new(value)
    end
  end
end

我正在尝试验证的课程如下。基本上我需要验证日期是否在未来。我正在使用before_validation方法构建我的starting_at。所以我不知道如何处理(A)它无法正确构建日期的情况(在用户删除我需要告诉用户填写日期的情况下)(B)如果我这样做的话构造它,然后它失败了保存,我不知道如何让它回到视图来纠正信息。

proposed_times.rb

belongs_to :meeting, :inverse_of => :proposed_times
validate :future_enough
before_validation :construct_starting_at
...
def future_enough
  unless starting_at && starting_at >= (Time.now + 15.minutes)
    errors.add(:not_far_enough_out, "msg not used but: starting_at isn't far enough out")
  end
end

def construct_starting_at
  if date.present? && time.present? && timezone.present?
    begin
      d = Time.parse(date)
      self.starting_at = Time.zone.parse("#{d.year}-#{d.month}-#{d.day} #{time.hour}:#{time.min}:00 #{timezone}")
    rescue
      self.starting_at = nil
    end
  end
end

这是我正在使用的视图。我知道这不是处理此功能的最佳方式,但我正在使用我所拥有的...我所做的一切都重定向到thank_you。我不确定为什么它没有失败。

meeting_controller.rb

def propose_times
  @consultation = Consultation.find(params[:id])
  @user = current_user

  # If this is coming second time around with data to save
  if request.put?
    @consultation.attributes = params[:consultation]
    if @consultation.save
      redirect_to thank_you_path
    else
      render :layout => "simple"
    end
  else
    render :layout => "simple"
  end
end

验证嵌套对象和处理错误的正确方法是什么?我是否需要将new_record?用于before_validation方法?

更新:因此,使用@Aditya建议的validates_associated,它仍然不会仅验证更新的数据。我输入的更新时间得到验证...但由于它们无效,它们不会保留,然后再次验证(使用旧数据)然后验证通过/失败并显示这些日期的警告

我错过了什么?

更新2 :我添加了一堆p语句来查看事件的顺序,如果我遗漏了validated_associated,那么它只会被验证一次,但由于某种原因,会议本身保存良好,因此它重定向到谢谢你。但是,如果我把它留在里面,它会验证两次,因此问题。那么为什么要验证第一个(或第二个)时间以及如何阻止它?

更新3 :好的,所以我拿出了我的proposed_times_attributes=功能,并在视图中添加了时区。这解决了问题(以及@Aditya的方法)。我希望我知道如何使用这样的定义方法。我尝试了使用/不拥有validates_associatedaccepts_nested_attributes_for以及定义该功能的各种其他组合。

所以如果你碰到这个,并碰巧知道如何写proposed_times_attributes=所以验证仍然有效,请告诉我。我需要能够将时区放在proposed_times_attributes=因为view我想为所有的proposed_times设置一个时区选择框。我希望有一种方法可以在*_attributes=()方法中调用super()。

2 个答案:

答案 0 :(得分:1)

终于明白了。因此,您可以通过调用assign_nested_attributes_for_collection_associationassign_nested_attributes_for_one_to_one_association来执行super()类型的方法。但您还需要调用accepts_nested_attributes_for以设置这些方法的一些选项(单击函数名称以查看每个方法的文档)。

accepts_nested_attributes_for :advisor, :client, :proposed_times
...
def proposed_times_attributes=(attributes)
  attributes.each do |key,value|
    value[:timezone] = client.timezone
  end
  assign_nested_attributes_for_collection_association(:proposed_times, attributes)
end

答案 1 :(得分:0)

@RyanJM

如果您使用以下

,则无需手动验证子关联实体

<强> meeting.rb

validates_associated :proposed_times

假设您在 meeting.rb

中已经拥有以下关联
has_many :proposed_times