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

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

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

有帮助吗?

解决方案

我实际上在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-accepted-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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top