更具体地说, “如何验证模型是否至少需要创建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散列中的嵌套任务属性将生成有效任务,此验证实际上正常工作。但是,如果他们生成无效的任务,那么任务将不会被创建,您最终会得到一个少于2个任务的项目,因此无效项目对象。
据我了解,这是因为在尝试保存任务之前,它无法确定任务属性是否有效,并且因为 - 据我所知 - 任务无法在项目之前保存,项目不知道任务是否有效。我假设这是正确的吗?
无论如何,我希望会有一个快速的答案,但它似乎不像我希望的那么简单。如果您有任何建议,我们将不胜感激。
答案 0 :(得分: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。
答案 1 :(得分:0)
SET CONSTRAINTS DEFERRED可能很有用。
否则,可能会编写一个存储过程来执行插入操作,然后说它是存储过程的可靠性,以确保只插入正确的,经过验证的数据。
答案 2 :(得分:0)
模型方法valid?
在模型对象保存之前运行验证。因此,验证关联的简单方法是使用validates_with_block' or '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