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

Vla*_*ski 2 ruby validation ruby-on-rails unique conditional-statements

我在播放列表模型中进行了以下验证,其中包含属性title和is_deleted.'is_deleted'列(bool类型列,默认值为'false')的要点是因为我必须存档播放列表而不删除它们.

validates :title, presence: true, uniqueness: true, unless: :is_deleted?
Run Code Online (Sandbox Code Playgroud)

现在,如果我有一个标题为'播放列表1'并且is_deleted为false的记录并尝试使用is_deleted创建一条记录:true它将不会验证他,这很好.如果我尝试将is_deleted列从第一个记录更新为true,它将不会验证,这也是好的.
但现在我有两个标题播放列表:"播放列表1"和is_deleted:true.如果我尝试将它们中的任何一个更新为is_deleted:false,验证将不会让我.它给出了"标题已被采取"错误.我真的不明白为什么,因为我没有任何其他记录是is_deleted:false标题:"播放列表1".

Sha*_*ell 5

这是因为您的验证仅检查唯一性:title.在更改is_deleted为模型后验证模型时,false检查标题是否唯一.它会进行如下查询:

Playlist.where(title: 'Playlist 1').where.not(id: self.id).exists?
Run Code Online (Sandbox Code Playgroud)

显然已经一个带有该标题的播放列表.

关键是它不会检查其他播放列表is_deleted上的标志.它仅在当前播放列表中使用它来决定是否应该验证.

您可能需要我们validates_uniqueness_of而不仅仅是validates这意味着您可以为验证添加条件:

validates_uniqueness_of :title, 
  unless: :is_deleted?, 
  conditions: -> { where(is_deleted: false) }
Run Code Online (Sandbox Code Playgroud)

这将确保您的唯一性检查仅检查也未删除的其他播放列表.

您需要保持validates :title, presence: true, unless: :is_deleted?验证标题是否存在(或者您可以使用allow_nilallow_blank选项取得一些成功validates_uniqueness_of).