我在播放列表模型中进行了以下验证,其中包含属性title和is_deleted。 'is_deleted'列(bool类型列,默认值为'false')的重点是因为我必须归档 播放列表不会删除它们。
validates :title, presence: true, uniqueness: true, unless: :is_deleted?
现在,如果我有一个标题为'播放列表1'并且is_deleted为false的记录,并尝试使用is_deleted创建一个记录:true它将不会验证他,这很好。如果我尝试将第一条记录中的is_deleted列更新为true,它将无法验证,这也很好。
但现在我有两个标题播放列表:“播放列表1”和is_deleted:true。如果我尝试将它们中的任何一个更新为is_deleted:false,验证将不会让我。它给出了“标题已被采取”错误。我真的不明白为什么,因为我没有任何其他记录是is_deleted:false标题:“播放列表1”。
答案 0 :(得分:5)
这是因为您的验证仅检查:title
的唯一性。在将is_deleted
更改为false
后验证模型时,它会检查标题是否唯一。它会执行以下查询:
Playlist.where(title: 'Playlist 1').where.not(id: self.id).exists?
显然已经一个已经有该标题的播放列表。
关键是它没有检查其他播放列表上的is_deleted
标记。它仅在当前播放列表中使用它来决定是否应该验证。
您可能需要我们validates_uniqueness_of
,而不仅仅是validates
,这意味着您可以为验证添加条件:
validates_uniqueness_of :title,
unless: :is_deleted?,
conditions: -> { where(is_deleted: false) }
这将确保您的唯一性检查仅检查其他未删除的播放列表。
您需要让validates :title, presence: true, unless: :is_deleted?
验证标题是否存在(或者allow_nil
上的allow_blank
或validates_uniqueness_of
选项可能会取得一些成功。< / p>
答案 1 :(得分:3)
这个unless
在ruby-land中运行。它完成了它在锡上的说法:“如果帖子没有被删除,则验证标题的唯一性”。请注意,它没有说“仅在未删除的记录中验证标题的唯一性”。
您应该使用数据库工具来强制执行此类限制。 Postgres有partial unique indexes可以做到这一点。