2013-04-23 5 views
5

ネストしたアトリビュートのバリデーションを自分のレールアプリで実行するには、何時間も苦労しています。小さな注意点は、親の属性に基づいてネストされた属性を動的に検証しなければならないことです。Railsはトランザクショナルオブジェクトのaccepts_nested_attributes_forを受け入れます。

私の設定は次のとおりです。私は多くの異なる関連モデルを持つ親があり、親を保存するたびにそれらのネストされた属性を検証したいと考えています。私が保存したいとき、私は親にupdate_attributesを呼んで私のコントローラで

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 

:検証が動的に変化しているという事実を考えると、私はモデルのカスタム検証メソッドを書かなければなりませんでした。今問題は、明らかに、レールはデータベースに対して検証を実行し、ユーザーまたはコントローラによって修正されたオブジェクトに対しては検証を実行しないということです。したがって、子供の価値はユーザーによって消去され、検証は合格しますが、データベースの項目が有効でないために後の検証は合格しません。

ここでは、このシナリオの簡単な例です:

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

子供に次の検証で、この

ためvalidates_associatedを使うべきだと思います。それはタイプミスかもしれません。 1. '子供の価値は空白にすることはできません' - 一重引用符内の一重引用符。 2. && parent.status = 'validate_children' - これは比較ではありません。その割り当て –

+0

オタクについて申し訳ありません!ここのコードは、私のアプリの単なる単純な例ですので、それは働いていない理由ではありませんが、それを指摘してくれてありがとう:) –

答えて

2

は、私はあなたのコード内のいくつかのエラーがあります

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

こんにちはSanthosh、非常に迅速な答えに感謝!私はすでにvalidates_associatedに足を踏み入れましたが、ここでの一般的な感覚は、何よりも面倒です。自分のモデルに触れずに、親のモデルからのみ関連付けられたレコード属性を検証する方法はありますか?私のセットアップでは、子供が値なしでデータベースに居ることができますが、親のステータスが 'validate_children'と異なる場合にのみ必要です。 –

+0

その場合、次のような子どもにバリデーションを追加することができます:validates:value、:presence => true、:if => "self.parent.status == 'validate_children'" –

+0

Hey Santhosh、問題は、私のアプリが例より少し複雑であり、多態的な関連付けも含まれているため、親レベルで検証を続けるほうがはるかに良いでしょう。私はちょうど最初のレベルのネストされたモデルで検証が動作することを理解しましたが、深いネストされたモデルではありません。例えば。子供が説明を持っている場合、その検証は子供のために働くが、その説明のためではない。 –

関連する問題