Ruby Sequel.migration中的不区分大小写的唯一性验证

Qsa*_*rio 1 ruby migration email-validation sequel

我正在尝试找出一个很好的验证,以便在我的迁移中使用,这需要对用户电子邮件地址不区分大小写.简而言之,我想要的东西就像validate :email, :uniqueness => {:case_sensitive => false}无需转换所有东西来使用Rails或ActiveRecord.我可以通过正则表达式运行电子邮件,但我不喜欢这种解决方案.

我找到了一条评论[1]说你可以使用,
validates_unique(:email){ |ds| ds.opts[:where].args.map! { |x| Sequel.function(:lower, x)}; ds}
但我不明白那段代码在做什么,当我不知道那个ds对象是什么或者一切都在发生时我不想使用那些代码(为什么map!, PostgreSQL拥有Sequel.function:lower?......也许,但我不知道.)

[1] http://comments.gmane.org/gmane.comp.lang.ruby.sequel/6447

所以我需要回答两件事之一:
1)如何在纯粹的Sequel.migration(没有ActiveRecord,没有Rails)中执行不区分大小写的唯一性验证?
- 或者 -
2)如果我在网上发现的代码片段实际上是我想要的,它做什么以及它是如何工作的?(ds对象是什么以及此验证对我的数据库有何作用?)

Jer*_*ans 5

正如Tin Man所提到的,你正在混淆验证和限制.你说你试图添加约束并谈论Sequel.migration,但那些与验证无关.

如果要添加数据库约束,则需要在迁移中执行以下操作:

alter_table(:table){add_unique_constraint Sequel.function(:lower, :email)}
Run Code Online (Sandbox Code Playgroud)

这样做是为了使数据库不允许以不区分大小写的方式重复发送电子邮件.

验证仅用于向用户呈现良好的错误消息.它们在保存之前运行,以便代替数据库引发异常(这很难处理),您会收到一条很好的错误消息.

就像那条评论所提到的那样,你不能在没有hack的情况下对case敏感数据库使用validates_unique进行不区分大小写的查找.这将要求validates_unique接受另一个选项(可能在将来添加).

如果你不想使用这样的黑客,你将不得不手动进行验证:

dataset = model.where{|o| {o.lower(:email)=>o.lower(email)}}
dataset.exclude(pk_hash) unless new?
errors.add(:email, 'is already taken') unless ds.count == 0
Run Code Online (Sandbox Code Playgroud)

就黑客所做的而言, ds是一个用于检查唯一性的Sequel::Dataset实例validates_unique.如果你这样做validates_unique :email,它将是这样的:

model.where(:email=>email)
# WHERE email = 'some email'
Run Code Online (Sandbox Code Playgroud)

ds.opts[:where]从该数据集中提取where子句,并转换参数,将它们包装在SQL lower函数调用中,以便转换where子句,使其类似于:

model.where{|o| {o.lower(:email)=>o.lower(email)}}
# WHERE lower(email) = lower('some email')
Run Code Online (Sandbox Code Playgroud)

这是一个黑客,因为它只有在模型的数据集尚未过滤时才有效.