1

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

我发现一条评论 [1] 说您可以使用,但我不明白该代码在做什么,并且当我不知道该对象是什么或发生了
validates_unique(:email){ |ds| ds.opts[:where].args.map! { |x| Sequel.function(:lower, x)}; ds}
什么时,我不想使用该代码(为什么, postgresql 有of吗? ...可能,但我只是不知道。)dsmap!Sequel.function:lower

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

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

4

1 回答 1

6

正如 Tin Man 提到的,您混淆了验证和约束。您说您正在尝试添加约束并谈论Sequel.migration,但这些与验证无关。

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

alter_table(:table){add_unique_constraint Sequel.function(:lower, :email)}

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

验证只是为了向用户呈现漂亮的错误消息。它们在保存之前运行,这样您就不会得到一个很好的错误消息,而不是数据库引发异常(这很难处理)。

就像评论提到的那样,您不能使用 validates_unique 对区分大小写的数据库进行不区分大小写的查找而无需破解。这将要求 validates_unique 接受一个附加选项(将来可能会添加)。

如果您不想使用这样的 hack,则必须手动进行验证:

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

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

model.where(:email=>email)
# WHERE email = 'some email'

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

model.where{|o| {o.lower(:email)=>o.lower(email)}}
# WHERE lower(email) = lower('some email')

这是一个 hack,因为它仅在模型的数据集尚未过滤时才有效。

于 2012-07-12T14:57:49.383 回答