2

更具体地说,“如何验证模型是否需要创建至少 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 个任务的项目,因此是一个无效的项目对象。

据我了解,这是因为它无法确定任务属性是否有效,直到它尝试保存任务,并且因为 -据我所知- 在项目之前无法保存任务,该项目不知道任务是否有效。我的假设是否正确?

无论如何,我希望会有一个快速的答案,但它似乎没有我希望的那么微不足道。如果您有任何建议,将不胜感激。

4

3 回答 3

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。

于 2009-07-01T14:53:36.850 回答
0

如果您的数据库引擎支持,则 SET CONSTRAINTS DEFERRED 可能很有用。

否则,可能会编写一个存储过程来进行插入,然后说它是存储过程的责任,以确保只插入正确的、经过验证的数据。

于 2009-06-17T00:38:12.733 回答
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-validatordm-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
于 2009-06-19T16:14:31.290 回答