如何有条件地添加索引

leo*_*may 3 activerecord ruby-on-rails

说我有一个模型

class Post < ActiveRecord::Base
  validates_uniqueness_of :title, :unless => Proc.new {|p| p.deleted?}
end
Run Code Online (Sandbox Code Playgroud)

限制是我只能有 1 个帖子的标题是“foobar”,而它没有被删除,还有 1 个以上的帖子,这些帖子都被删除了,而且标题是“foobar”。由于 ActiveRecord 无法保证此链接中标题的唯一性,因此我尝试在表帖子中添加唯一索引,在列 [:title, :deleted] 上,当我尝试插入新的内容时,该方案将失败删除帖子到数据库。

vee*_* yh 15

在 postgresql 中是可能的

add_index :table_name, :columns, unique: true, where: "(deleted_at IS NULL)"
Run Code Online (Sandbox Code Playgroud)


Cam*_*lsh 1

大多数数据库(例如 MySQL)不可能有条件数据库索引。

如果您绝对必须保证唯一性,最好的选择可能是拥有一个单独的已删除帖子表。您在主表上有唯一索引,但在包含已删除记录的表上没有。您最终会得到更小的帖子表和更简单的编码 - 不再需要在任何查询中过滤掉已删除的帖子。

您是否考虑过如果取消删除帖子会发生什么 - 两个帖子可以具有相同的标题吗?

其他一些选项是:

  1. 删除帖子时更改标题,例如添加时间戳。
  2. 如果您可以找到 2 个或更多相同标题的实例,则在保存模型后引发异常。
  3. 保存之前锁定整个表(悲观锁定)。
  4. 只是希望它能起作用(你多久会有两个人在同一时间发布相同的标题?)