Railsモデルの1つで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.create!(
:name => 'Something',
:task_attributes => [ { :name => '123' }, { :name => '456' } ]
)
プロジェクトモデルを保存すると、プロジェクトが保存されていないため、project_idがないため、タスクの検証が失敗します。
Railsは以下のパターンに従っているようです:
パターンは次のとおりです。
だから私の質問は次のように要約されます:親(プロジェクト)が保存された後、Railsを実行してproject_id =(またはproject =)メソッドを実行し、子(タスク)で検証する方法は?ただし、子(タスク)が無効な場合、親(プロジェクト)モデルは保存しませんか?
何か案は?
Rails 2の場合はこの回答を使用します。それ以外の場合は、:inverse_of
回答
notで関連するプロジェクトが有効かどうか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
使用する :inverse_of
およびvalidates_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
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
残念ながら、上記の提案はどれもRails 2.3.5。
私の場合、ネストされた属性を使用して両方が作成されている場合、タスク内のプロジェクトは常にnilです。 validates_presence_ofを削除した場合のみ、作成は正常に行われます。単体テストとログは、すべてが正しく作成されたことを示しています。
したがって、Railsの代わりにDBに制約を追加する傾向があります。そもそもそれがより信頼性が高いようです。
プロジェクトを作成し、検証に合格した場合にのみプロジェクトを追加できます。
tasks = params.delete(:task_attributes)
if Project.create(params)
Project.update_attributes(:task_attributes => tasks)
end
チャオ
Bigoの提案とは逆に、最初に親オブジェクトを保存してから子を保存することは常に許容できるわけではありません。通常、オブジェクトの保存を開始する前に、すべてのオブジェクトを検証する必要があります。これにより、ユーザーは入力フォームを再編集してエラーを修正できます。
あなたが説明する問題はRails 3.0で修正されます。Lighthouseチケットへのリンクを投稿したはずですが、私は新しいユーザー(#fail)なので、stackoverflow.comではこれを許可していません。 。しかし、当面は、「バグ」を修正するプラグイン「 parental_control 」を使用できます。