2009-06-01 13 views
69

私はRailsモデルでaccepts_nested_attributes_forを使用しています。親を作成した後に子を保存したいと思います。accepts_nested_attributes_for子の関連付けの検証に失敗する

フォームは完全に機能しますが、検証に失敗しています。簡単にするため、次のを想像してみてください。

class Project < ActiveRecord::Base 
    has_many :tasks 
    accepts_nested_attributes_for :tasks 
end 

class Task < ActiveRecord::Base 
    belongs_to :project 

    validates_presence_of :project_id 
    validates_associated :project 
end 

そして、私は実行しています:以来、彼らは(PROJECT_IDを持っていないので、

Project.create!(
    :name => 'Something', 
    :task_attributes => [ { :name => '123' }, { :name => '456' } ] 
) 

をプロジェクトモデルを保存すると、検証がタスクに失敗していますプロジェクトは保存されていません)。

  • 検証プロジェクト
  • 検証作業
  • プロジェクトの保存
  • 保存作業

パターンは次のようになります:

Railsは以下のパターンに従っているように思え

    パスで
  • 検証プロジェクト
  • :パス上のプロジェクトを保存して続行...
  • 検証作業
    • :失敗でタスク
    • を保存:プロジェクト(?たぶんロールバック)
  • を削除します。

私の質問には、次のようなものがあります。どのようにして、Railsにproject_id =(またはproject =)メソッドと子プロセスの検証を実行させることができますか? (プロジェクト)が保存されましたが、子(タスク)が無効な場合、親(プロジェクト)モデルを保存しないでください。

アイデア?

答えて

12

使用この答えを、そうでなければ、関連するプロジェクトが有効であるかどうPROJECT_IDをチェックないによってこの問題を回避することができます:inverse_of答え

については、以下を参照してください。


class Task < ActiveRecord::Base 
    belongs_to :project 

    validates_presence_of :project_id, :unless => lambda {|task| task.project.try(:valid?)} 
    validates_associated :project 
end 
+0

これは私のために動作しませんでした。 validates_presence_of:project_idの呼び出しで、 'project'はnilを返してproject_idを検証し、検証を失敗させます。私は問題が異なると思ったので別の質問を作成しましたが、それは同じであるようですhttp://stackoverflow.com/questions/2102724/rails-nested-attributes-association-validation-failing。 –

+10

以下の解決策のinverse_ofは、Rails 3.0以上でより正確です。 – nertzy

1

あなただけのプロジェクトを作成し、唯一それが検証に合格した場合、プロジェクトを追加することができます。

tasks = params.delete(:task_attributes) 
if Project.create(params) 
    Project.update_attributes(:task_attributes => tasks) 
end 

チャオ

0

反して、それは最初にして親オブジェクトを保存するために、常に許容ではありません、示唆するものビーゴに子どもたち。通常は、オブジェクトの保存を開始する前に、すべてのオブジェクトの妥当性を確認する必要があります。これにより、入力フォームを再編集してエラーを修正する機会がユーザに与えられます。

あなたが記述した問題は、Rails 3.0で修正される予定です。私はLighthouseチケットへのリンクを掲示していましたが、私が新しいユーザー(#fail)であるため、stackoverflow.comはこれを許可しません。しかし当面は、プラグイン "parental_control"を使用すると、 "バグ"が修正されます。Railsの2のための

2

残念ながら、上記の提案はどれもRails 2.3.5ではうまくいきません。

私の場合、ネストされた属性を使って両方のプロジェクトを作成すると、タスクのプロジェクトは常にnilになります。 validates_presence_ofを削除した場合のみ、作成は正常に完了します。ユニットテストとログは、すべてが正しく作成されたことを示しています。

私は今、Railsの代わりにDBに制約を加える傾向があります。これは、最初はより信頼性が高いようです。

8

だけの関係ではなく、IDを検証:できるだけ早く関連が人口であるよう

class Task < ActiveRecord::Base 
    belongs_to :project 

    validates_presence_of :project 
end 

を、ActiveRecordの検証は、モデルが保存されているかどうか、成功したとみなします。あなたは、タスクのプロジェクトが常に保存されていることを確認するために、同様に自動保存を調査する場合があります

class Task < ActiveRecord::Base 
    belongs_to :project, :autosave => true 

    validates_presence_of :project 
end 
+0

最後に私が探していた答え。 – doug

159

使用:inverse_ofvalidates_presence_of :parent。これにより、検証の問題が解決されます。

class Dungeon < ActiveRecord::Base 
    has_many :traps, :inverse_of => :dungeon 
    end 

    class Trap < ActiveRecord::Base 
    belongs_to :dungeon, :inverse_of => :traps 
    validates_presence_of :dungeon 
    end 

http://apidock.com/rails/ActiveModel/Validations/HelperMethods/validates_presence_of

https://github.com/rails/rails/blob/73f2d37505025a446bb5314a090f412d0fceb8ca/activerecord/test/cases/nested_attributes_test.rb

+3

Rails 3.0で私のために働いた –

+1

ありがとう!これは美しく働きました、そして、私は他のどこにでもそれについて多くの言及を見たことがありません。 – Emily

+0

Rails 3.2.3用の未定義メソッド 'validate_presence_of '。行はvalidates_presence_of:dungeonでなければなりません。 – simeonwillbanks

関連する問題