2

我以复杂形式使用多个子模型(la http://railsforum.com/viewtopic.php?id=28447)。表单很好,但我需要在接受表单数据到数据库之前验证子模型的集合的属性。我已经想出了一个主要工作,很笨拙的做法。似乎有必要有更好的方式,所以我要求建议...验证复杂形式的多个子模型的rails

基本上一个人has_many分布。分配(除其他外)具有百分比属性。对于一个给定的人,他们的分布必须总计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的过程中将参数本身作为文本处理。但那只是错误的。 :)

其他人对整个孩子集合进行验证?什么是正确的方式去做呢?

回答

2

我不建议在update_attributes中设置错误。在正常的地方保持验证。

回到您的问题,您是否可以更改验证检查以处理内存中的分发,而不是在数据库上执行计算?

# in Person model 
validate :ensure_distributions_equal_100 

def ensure_distributions_equal_100 
    percent = distributions.map(&:percent).sum 
    if percent != 100 
    errors.add_to_base("Distribution must add up to exactly 100%, they are #{percent}") 
    end 
end 
+0

是的,谢谢,一旦我想出内存与DB角度,我写了一个函数作为验证。 :) 我仍然有问题,如果验证失败(一些挂起的更改丢失,但不是全部),编辑视图得到呈现,但这是一个不同的错误! – korinthe 2009-08-26 17:44:27