我有一个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
我如何实现这个?
对不起格式错误,从手机输入。
答案 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
(并且 NULL
为 deleted_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