独特的约束问题偏执狂宝石

时间:2016-09-05 14:15:47

标签: ruby-on-rails postgresql activerecord devise ruby-paranoia

我有一个rails应用程序,我正在使用设计和偏执宝石 我在postgres db中有一个用户表,它在电子邮件列上有唯一的验证。 我使用偏执狂进行软删除,问题是当我删除用户然后使用已删除用户的电子邮件创建用户时会抛出错误PG::UniqueViolation: ERROR
我已经读过这个并且知道这可以使用rails的部分索引功能来解决。

http://scottsmerchek.com/2015/08/03/taking-the-d-out-of-crud/

https://devcenter.heroku.com/articles/postgresql-indexes#partial-indexes

我如何实现这个?
对不起格式错误,从手机输入。

4 个答案:

答案 0 :(得分:3)

由于您将用户删除为软删除,以便电子邮件无法从数据库中删除,因此只有用户属性is_deleted设置为true。

现在要解决PG::UniqueViolation: ERROR,您必须在字段电子邮件和deleted_at上创建唯一索引 所以你的迁移将是

class AddUniqueIndexToUsers < ActiveRecord::Migration
  def change
    remove_index :users, column: :email
    add_index :users, [:email, :deleted_at], unique: true
  end
end

答案 1 :(得分:0)

Rakesh 的答案是错误的,并且会允许在数据库中出现重复项,因为当其中一个值为 UNIQUE(并且 NULLdeleted_at 时,复合 NULL 索引将失败)默认)。

要完成这项工作,您实际上需要以相反的方式将这种细微差别与唯一索引一起使用,您可以拥有一个整数列,例如 acive:tinyint (default 1) 和一个复合索引,如下所示:

add_index :users, [:email, :active], unique: true

创建新用户时无需特殊操作,因为 active 列的默认值为 1。但是每次删除记录时,除了设置 deleted_at 外,还需要将 active 设置为 NULL。这样一来,您就可以使用相同的电子邮件地址只删除一个活动记录,并删除许多记录。

在 PostgreSQL 或 MySQL > 8.0.13 中,您可以在没有此附加列的情况下工作并使用如下功能索引:

CREATE UNIQUE INDEX unique_email
                 ON users (email, (IF(deleted_at IS NULL, 1, NULL)));

结果将类似于带有 active 列的示例。删除一条记录后,该记录的唯一索引将停止工作,从而允许您拥有多个具有相同 email 的已删除记录。

答案 2 :(得分:0)

它会在 Postgresql 上失败,可能的解决方案是

class AddUniqueIndexToUsers < ActiveRecord::Migration
  def change
    remove_index :users, column: :email
    add_index :users, [:email, :deleted_at], unique: true, where: "deleted_at is null"
  end
end

参考https://www.ironin.it/blog/partial-unique-indexes-in-postgresql-and-rails.html

答案 3 :(得分:0)

就够了:

class AddUniqueIndexToUsers < ActiveRecord::Migration
  def change
    remove_index :users, column: :email
    add_index :users, :email, unique: true, where: 'deleted_at IS NULL'
  end
end