我需要找到一种方法来获取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一样进行检查(保存后),但我真的很喜欢从验证中得到的安全感。)
答案 0 :(得分:2)
而不是使用sum-query命中数据库,你可以根据活动集合来计算这些东西
self.activities.map(&:hours).sum