Rails ActiveRecord - 使用命名范围验证唯一性(不像其他列那样的范围)
Rails ActiveRecord - vaildate uniqueness with named scope (not the scope like other columns)
想象一个用户 table:
id
email
access_token
refresh_token
country_id
city_id
discarded_at
1
james.dean@example.com
11111
22222
1
1
2021-01-31 00:57:25
2
james.bond@example.com
33333
44444
1
3
NULL
3
james.franco@example.com
55555
66666
2
4
NULL
4
james.corden@example.com
77777
88888
1
5
NULL
5
james.dean@example.com
11111
22222
1
1
NULL
通常,验证其他列的唯一性是这样的
validates :emails, :access_token, :refresh_token, uniqueness: { scope: %i[country_id city_id] }
现在的问题是 - 如何为命名范围执行此操作?
例如,有一个命名范围 scope :kept, -> { where(discarded_at: nil) }
,那么 email
、access_token
和 refresh_token
对于所有 kept
用户应该是唯一的。
(上面的例子,即ID=5是有效的,因为ID=1已经被丢弃,所以email,ID=5的access_token和refresh_token是有效的)
class User < ApplicationRecord
scope :kept, -> { where(discarded_at: nil) }
# maybe something like this?
validates :email, :access_token, :refresh_token, uniqueness: { where(discarded_at: nil) }
end
您可以使用 conditions
选项(如概述 here)
validates_uniqueness_of :email, :access_token, :refresh_token, conditions: -> { where(discarded_at: nil) }
只是为了进一步扩展@AbM 的回答以及@r4cc00n 的评论。
完整答案如下:
- 使用新的
validates
语法
- 需要
allow_nil
- 添加数据库级索引
型号
validates :email, :access_token, :refresh_token,
uniqueness: { allow_nil: true, conditions: -> { where(discarded_at: nil) } }
迁移
class CreateUniqueIndiceToUsers < ActiveRecord::Migration[6.0]
def change
add_index :users, :email, unique: true, where: "(discarded_at IS NULL)"
add_index :users, :access_token, unique: true, where: "(discarded_at IS NULL)"
add_index :users, :refresh_token, unique: true, where: "(discarded_at IS NULL)"
end
end
想象一个用户 table:
id | access_token | refresh_token | country_id | city_id | discarded_at | |
---|---|---|---|---|---|---|
1 | james.dean@example.com | 11111 | 22222 | 1 | 1 | 2021-01-31 00:57:25 |
2 | james.bond@example.com | 33333 | 44444 | 1 | 3 | NULL |
3 | james.franco@example.com | 55555 | 66666 | 2 | 4 | NULL |
4 | james.corden@example.com | 77777 | 88888 | 1 | 5 | NULL |
5 | james.dean@example.com | 11111 | 22222 | 1 | 1 | NULL |
通常,验证其他列的唯一性是这样的
validates :emails, :access_token, :refresh_token, uniqueness: { scope: %i[country_id city_id] }
现在的问题是 - 如何为命名范围执行此操作?
例如,有一个命名范围 scope :kept, -> { where(discarded_at: nil) }
,那么 email
、access_token
和 refresh_token
对于所有 kept
用户应该是唯一的。
(上面的例子,即ID=5是有效的,因为ID=1已经被丢弃,所以email,ID=5的access_token和refresh_token是有效的)
class User < ApplicationRecord
scope :kept, -> { where(discarded_at: nil) }
# maybe something like this?
validates :email, :access_token, :refresh_token, uniqueness: { where(discarded_at: nil) }
end
您可以使用 conditions
选项(如概述 here)
validates_uniqueness_of :email, :access_token, :refresh_token, conditions: -> { where(discarded_at: nil) }
只是为了进一步扩展@AbM 的回答以及@r4cc00n 的评论。
完整答案如下:
- 使用新的
validates
语法 - 需要
allow_nil
- 添加数据库级索引
型号
validates :email, :access_token, :refresh_token,
uniqueness: { allow_nil: true, conditions: -> { where(discarded_at: nil) } }
迁移
class CreateUniqueIndiceToUsers < ActiveRecord::Migration[6.0]
def change
add_index :users, :email, unique: true, where: "(discarded_at IS NULL)"
add_index :users, :access_token, unique: true, where: "(discarded_at IS NULL)"
add_index :users, :refresh_token, unique: true, where: "(discarded_at IS NULL)"
end
end