我正在以复杂的形式使用多个子模型(例如http://railsforum.com/viewtopic.php?id=28447)。表单效果很好,但在将表单数据接收到数据库之前,我需要验证子模型集的属性。我想出了一种主要工作,非常笨拙的方式来做到这一点。似乎必须有更好的方法,所以我正在寻求建议......
基本上一个人有很多分布。分布具有(除其他外)百分比属性。对于给定的人,他们的分配必须总计 100% 才有效。这对我来说是“交易”,但我认为我应该先给验证者一个机会。
我尝试将其编写为自定义验证器,但验证器仅适用于已保存到数据库中的数据。它没有检查表单提交的参数。换句话说,我能够通过表单输入无效的百分比,这些百分比被保存,然后由于模型中已经存在错误数据,随后的编辑都失败了。
接下来我在我的 Person 模型中扩展了 update_attributes,添加了一个事务:
def update_attributes(params)
retval = true
self.transaction do
retval = super
unless distributions_exactly_100?
retval = false
errors.add_to_base("Distribution must add up to exactly 100%")
raise ActiveRecord::Rollback
end
end
retval
end
retval 业务很丑陋,但这或多或少是有效的(有时,当它发现错误并重新渲染时,表单中会缺少一些待处理的分发版)。还有一个细微的差别让我相信这是一个糟糕的方法:如果我的分布关联是用辅助方法定义的,如下所示,我不能在我的update_attributes()
(或在distributions_exactly_100?
)中使用辅助方法,因为它们进入数据库而不是在刚刚分配但尚未提交的分布集上运行。
has_many :distributions do
def for_month_and_year(month, year)
find :all, :conditions => ['month = ? and year = ?', month, year]
end
def total_for_month_and_year(month, year)
sum :percentage, :conditions => ['month = ? and year = ?', month, year]
end
...
def years_and_months
ds = find(:all, :order => 'year DESC, month DESC')
(ds.collect {|d| [d.year, d.month]}).uniq
end
end
我能想到的唯一另一件事是在进入 update_attributes 的过程中将参数本身作为文本处理。但那是错误的。:)
还有其他人对整个儿童集合进行验证吗?正确的方法是什么?