除非条件不需要的行为,否则Rails唯一性验证

时间:2015-07-16 08:03:11

标签: ruby-on-rails ruby validation unique conditional-statements

我在播放列表模型中进行了以下验证,其中包含属性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”。

2 个答案:

答案 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_blankvalidates_uniqueness_of选项可能会取得一些成功。< / p>

答案 1 :(得分:3)

这个unless在ruby-land中运行。它完成了它在锡上的说法:“如果帖子没有被删除,则验证标题的唯一性”。请注意,它没有说“仅在未删除的记录中验证标题的唯一性”。

您应该使用数据库工具来强制执行此类限制。 Postgres有partial unique indexes可以做到这一点。