原标题:更新时的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_associated
,accepts_nested_attributes_for
以及定义该功能的各种其他组合。
所以如果你碰到这个,并碰巧知道如何写proposed_times_attributes=
所以验证仍然有效,请告诉我。我需要能够将时区放在proposed_times_attributes=
因为view我想为所有的proposed_times设置一个时区选择框。我希望有一种方法可以在*_attributes=()
方法中调用super()。
答案 0 :(得分:1)
终于明白了。因此,您可以通过调用assign_nested_attributes_for_collection_association
或assign_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