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