嵌套属性的自定义验证

时间:2013-07-31 00:22:21

标签: ruby-on-rails nested-attributes custom-validators

我需要找到一种方法来获取rails(3.2.8)以在对父对象执行验证之前保存嵌套属性。我已经搜索了很长时间来回答我的问题,虽然我发现了类似的问题,但我还没有看到一个优雅的解决方案。

情况如下:

我有一个activity_log,其中每个log_entry都有多个活动。 log_entry有一个名为“hours”的字段,表示当天的总工作时间。每个活动还有一个“小时”字段,表示在该活动上花费的时间。我需要确保log_entry.activities.sum(:hours)不大于log_entry.hours。

以下是代码:

class LogEntry < ActiveRecord::Base
  attr_accessible :date, :hours, :activities_attributes

  has_many :activities
  accepts_nested_attributes_for :activities

  validate :sum_hours_not_more_than_total_hours

  private
  def sum_hours_not_more_than_total_hours
    unless activities.sum(:hours) <= hours
      errors.add(:hours, "Hours cannot exceed total hours")
    end
  end
end

问题是它在计算activities.sum(:hours)时检查db,而不是检查params中的新数据。因此,如果我将log_entry的小时设置为4并创建一个小时设置为5的活动,它将保存没有错误(因为db表示activities.sum(:hours)== 0)。但是,如果我编辑同一条记录并将活动的小时数设置为4,则会产生错误(因为db表示activities.sum(:hours)== 5),它应该通过。

我在这里找到了一个解决方法:http://railsforum.com/viewtopic.php?id=41562,但我希望有更优雅的方法来解决这个问题。 (实际上,这个解决方案对我来说不起作用,因为它假设唯一的问题是记录传递的验证不应该。我也有问题,记录失败验证时应该通过。我想我可以解决它通过跳过验证步骤,然后像控制器中的sum_hours_not_more_than_total_hours一样进行检查(保存后),但我真的很喜欢从验证中得到的安全感。)

1 个答案:

答案 0 :(得分:2)

而不是使用sum-query命中数据库,你可以根据活动集合来计算这些东西

self.activities.map(&:hours).sum