71

Rails モデルの 1 つで accept_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.create!(
  :name => 'Something',
  :task_attributes => [ { :name => '123' }, { :name => '456' } ]
)

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

Rails は以下のパターンに従っているようです。

  • プロジェクトの検証
  • 検証タスク
  • プロジェクトを保存
  • タスクを保存

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

  • プロジェクトの検証
  • 合格時: プロジェクトを保存して続行...
  • 検証タスク
    • 合格時: タスクの保存
    • 失敗時: プロジェクトを削除します (ロールバックの可能性がありますか?)

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

何か案は?

4

6 に答える 6

163

とを使用: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

于 2011-01-24T14:26:42.040 に答える
12

:inverse_ofRails 2にはこの回答を使用してください。それ以外の場合は、以下の回答を参照してください

関連するプロジェクトが有効な場合、project_id をチェックしないことで、これを回避できます。


class Task < ActiveRecord::Base
  belongs_to :project

  validates_presence_of :project_id, :unless => lambda {|task| task.project.try(:valid?)}
  validates_associated :project
end
于 2009-09-16T01:15:17.930 に答える
9

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
于 2010-03-10T03:06:03.110 に答える
2

残念ながら、上記の提案はいずれも Rails 2.3.5 では機能しません。

私の場合、ネストされた属性を使用して両方が作成されている場合、タスク内のプロジェクトは常に nil です。validates_presence_of を削除した場合にのみ、作成が成功します。単体テストとログは、すべてが正しく作成されたことを示しています。

そのため、Rails の代わりに DB に制約を追加する傾向があるのは、そもそも信頼性が高いように思われるからです。

于 2010-03-09T11:22:56.103 に答える
1

プロジェクトを作成し、検証に合格した場合にのみプロジェクトを追加できます。

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

チャオ

于 2009-06-08T14:50:26.797 に答える
0

bigo の提案に反して、最初に親オブジェクトを保存してから子オブジェクトを保存することが常に受け入れられるとは限りません。通常、保存を開始する前に、すべてのオブジェクトが検証されることを確認します。これにより、ユーザーは入力フォームを再編集してエラーを修正することができます。

あなたが説明した問題は、Rails 3.0 で修正される予定です。Lighthouse チケットへのリンクを投稿したかったのですが、私は新しいユーザー (#fail) であるため、stackoverflow.com はこれを許可しません。しかし当分の間、「バグ」を修正するプラグイン「 parental_control 」を使用できます。

于 2009-08-03T16:53:30.187 に答える