ネストされたモデルを検証しますか?
-
05-07-2019 - |
質問
より具体的には、 "モデルで少なくともx個の有効な関連モデルを作成する必要があることを検証するにはどうすればよいですか? 。私は、親と同じ形式で作成されたネストされたモデルを検証しようとしました(そして最終的にはjQueryでの即時検証を表示します)。一般的な例として、次のモデルとスキーマを想定してみましょう。
class Project
include DataMapper::Resource
property :id, Serial
property :title, String, :nullable => false
has 2..n, :tasks
end
class Task
include DataMapper::Resource
property :id, Serial
property :project_id, Integer, :key => true
property :title, String, :nullable => false
belongs_to :project
end
すべての検証は、ご覧のとおりスキーマ定義で行われます。ここで重要なのは" has 2..n、:tasks
"です。 paramsハッシュのネストされたタスク属性が valid タスクを生成することを考えると、この検証は実際に正常に機能します。ただし、無効なタスクを生成した場合、タスクは作成されず、2つ未満のタスクを持つプロジェクトになります。したがって、無効な >プロジェクトオブジェクト。
私が理解しているように、これはタスクを保存しようとするまでタスク属性が有効かどうかわからないためです-私の知る限り-プロジェクトの前にタスクを保存することはできません。プロジェクトは、タスクが有効かどうかを認識しません。私はこれを仮定して正しいですか?
とにかく、すぐに答えが出ることを望んでいましたが、思っていたよりもささいなことではないようです。何か提案があれば、それは大歓迎です。
解決
実際に、DataMapperのトランザクションを使用して、ここで素晴らしいソリューションを見つけました。基本的に、このトランザクションは親オブジェクトとすべての子オブジェクトを保存しようとします。保存に失敗するとすぐに、トランザクションは停止し、何も作成されません。すべてがうまくいけば、オブジェクトは正常に保存されます。
class Project
def make
transaction do |trans|
trans.rollback unless save
tasks.each do |task|
unless task.save
trans.rollback
break
end
end
end
end
end
これにより、すべてが保存される前にすべてが有効になります。コントローラコードで#saveおよび#updateメソッドを#makeに変更する必要がありました。
他のヒント
SET CONSTRAINTS DEFERREDは、データベースエンジンがサポートしている場合に便利です。
それ以外の場合、ストアドプロシージャを作成して挿入を実行し、そのストアドプロシージャの妥当性を確認して、正しい検証済みデータのみが挿入されるようにします。
モデルオブジェクトが保存される前に検証を実行する valid?
というモデルメソッドがあります。したがって、関連付けを検証する簡単な方法は、 validates_with_block 'または' validates_with_method
を使用して、関連付けの検証をチェックすることです。
次のようになります
validates_with_block do
if @tasks.all?{|t|t.valid?}
true
else
[false, "you have an invalid task"]
end
end
または dm-association-validator または dm-accepts-nested-attributes
編集:クレイジーになります。タスクの検証を実行してから、関連付けに関連するエラーのみがエラーであるかどうかを確認します。
validates_with_block do
if @tasks.all?{|t|t.valid?;!t.errors.any?{|e|e[0]==:project}}
true
else
[false, "you have an invalid task"]
end
end