验证嵌套表单中工作不正常的子对象的唯一性



Rails中的作用域唯一性验证有问题。如果我尝试直接在子模型中创建一个具有相同属性集的新对象(我不想重复这些属性集),效果很好,但当我尝试创建具有两个不唯一子对象的父对象时,验证不会被触发。

背景

我在Rails3.2中有一个应用程序,它的视图在带有simple_form的HAML中。

我有两种型号:PageProperty。一个页面可以有许多属性,并且它接受属性的嵌套属性。

我想验证一个页面不能有两个同名的属性:

#app/models/page.rb
class Page < ActiveRecord::Base
  has_many :properties
  accepts_nested_attributes_for :properties, :allow_destroy => :true
end

#app/models/property.rb
class Property < ActiveRecord::Base
  belongs_to :page
  VALID_PROPERTIES = %w(id text name xpath class css)
  validates :name, :inclusion => VALID_PROPERTIES, :uniqueness => {:scope => :page_id}
end

当然,该属性有一个page_id属性。

正如我所说,当通过表单创建新属性时,验证是有效的。如果我试图创建一个具有相同名称和相同page_id的新属性,Rails告诉我已经取了这个名称。

问题

如果我创建了一个新页面,并通过嵌套表单分配各种属性,我就可以绕过此验证。当数据库中还没有page_id和property_id的组合时,这似乎只是一个问题,因此,例如,如果我编辑了一个已经保存了属性的page模型,并尝试添加一个同名的新模型,那么现在就会触发验证。

我会尝试使用validates_associated:

class Page < ActiveRecord::Base
  has_many :properties
  accepts_nested_attributes_for :properties, :allow_destroy => :true
  validates_associated :properties 
end

更新

Rails验证指南指出:

通过对模型的表,搜索中具有相同值的现有记录属性

您正在创建的2Properties对象在数据库中还不存在,因此唯一性验证无法工作。您应该尝试使用自定义验证

class Property < ActiveRecord::Base
  #...
  validate :name, :name_uniqueness
  def name_uniqueness 
    self.page.properties.select {|p| p.key == self.key}.size == 1
  end
end

最新更新