2013-04-23 70 views
5

爲了驗證嵌套屬性在我的Rails應用程序中工作幾個小時,我很掙扎。需要注意的一點是,我必須根據父級的屬性動態驗證嵌套屬性,因爲根據父級進程中的位置,所需信息的數量隨時間而變化。Rails的accept_nested_attributes_for對交易對象進行驗證

因此,這裏是我的設置:我有一個父與許多不同的關聯模型,我想驗證隨後嵌套的屬性,每次我保存父。鑑於驗證動態變化,我不得不寫在模型中定義驗證方法:

class Parent < ActiveRecord::Base 
    attr_accessible :children_attributes, :status 
    has_many :children 
    accepts_nested_attributes_for :children 
    validate :validate_nested_attributes 
    def validate_nested_attributes 
    children.each do |child| 
     child.descriptions.each do |description| 
     errors.add(:base, "Child description value cant be blank") if description.value.blank? && parent.status == 'validate_children' 
     end 
    end 
    end 
end 


class Child < ActiveRecord::Base 
    attr_accessible :descriptions_attributes, :status 
    has_many :descriptions 
    belongs_to :parent 
    accepts_nested_attributes_for :descriptions 
end 

在我的控制器時我要救我呼籲家長update_attributes方法。現在的問題是,顯然,rails會針對數據庫運行驗證,而不是針對用戶或控制器修改的對象。因此,可能發生的情況是,用戶刪除了孩子的值,並且驗證將通過,而後來的驗證將不會通過,因爲數據庫中的項無效。

下面是這種情況的一個簡單的例子:

parent = Parent.create({:status => 'validate_children', :children_attributes => {0 => {:descriptions_attributes => { 0 => {:value => 'Not blank!'}}}}) 
    #true 
parent.update_attributes({:children_attributes => {0 => {:descriptions_attributes => { 0 => {:value => nil}}}}) 
    #true!!/since child.value.blank? reads the database and returns false 
parent.update_attributes({:children_attributes => {0 => {:descriptions_attributes => { 0 => {:value => 'Not blank!'}}}}) 
    #false, same reason as above 

驗證適用於一級協會,例如如果一個Child有一個'value'屬性,我可以按照我的方式運行驗證。問題在於深度關聯顯然無法在保存之前進行驗證。

任何人都可以指出我如何解決這個問題的正確方向?我目前看到的唯一方法是保存記錄,事後驗證它們,並在驗證失敗時刪除/恢復它們,但我誠實地希望有更清潔的東西。

謝謝大家提前!

SOLUTION

因此,原來我是通過直接在定製驗證引用那些運行於深嵌套模型的驗證,這種方式:

class Parent < ActiveRecord::Base 
    [...] 
    has_many :descriptions, :through => :children 
    [...] 
    def validate_nested_attributes 
    descriptions.each do |description| 
     [...] 
    end 
    end 
end 

由於某種原因導致的問題我在上面。感謝Santosh測試我的示例代碼並報告它正在工作,這指出我在正確的方向弄清楚了這一點。

爲了將來的參考,原始問題中的代碼適用於這種動態的,深度嵌套的驗證。

+0

有在你的代碼一些錯誤。它可能是錯字。 1.「兒童價值不能爲空」 - 單引號內的單引號。 2. && parent.status ='validate_children' - 這不是比較。它的任務 – 2013-04-23 11:21:22

+0

抱歉錯別字!這裏的代碼只是我的應用程序的一個簡化的例子,所以這不是它不工作的原因,但感謝指出:) – 2013-04-23 11:39:03

回答

2

我想你應該在孩子這個

使用validates_associated與下面的驗證

validates :value, :presence => true, :if => "self.parent.status == 'validate_children'" 
+0

嗨Santhosh,感謝您的快速答案!我已經介入validates_associated,但在這裏的總體感覺是,它比任何事情更麻煩。有沒有一種方法可以在不觸及自己的模型的情況下驗證僅來自父級模型的關聯記錄屬性?這將是必要的,因爲在我的設置中,孩子可以在沒有值的情況下居住在數據庫中,但只有當父母的狀態與「validate_children」不同時。 – 2013-04-23 10:39:00

+0

在這種情況下,你可以像這樣在孩子中添加驗證:validates:value,:presence => true,:if =>「self.parent.status =='validate_children'」 – 2013-04-23 11:20:18

+0

嗨Santhosh,再次感謝您的回覆。問題是我的應用程序比示例稍微複雜一點,它也涉及多態關聯,因此在父級保持驗證會更好。我只是想出了在第一級嵌套模型上的驗證,但它們不在深層嵌套模型上。例如。如果孩子有描述,驗證將適用於兒童,但不適合他們的描述。 – 2013-04-23 11:31:09