gpt4 book ai didi

mysql - 如何在不区分大小写的情况下指示 Rails 在唯一性验证上生成正确的 SQL

转载 作者:可可西里 更新时间:2023-11-01 06:37:38 24 4
gpt4 key购买 nike

假设 Rails 3 与 MySQL 数据库不区分大小写

故事是什么:

Rails 允许您使用“唯一性”验证器来验证模型的属性。但是根据 Rails 文档,默认比较是区分大小写的。

这意味着在验证时它会执行如下 SQL:

SELECT 1 FROM `Users` WHERE (`Users`.`email` = BINARY 'FOO@email.com') LIMIT 1

对于拥有带 CI 整理的数据库的我来说,这完全是错误的。它会认为'FOO@email.com'有效,即使用户表中已经有另一个用户'foo@email.com'。换句话说,这意味着,如果应用程序的用户尝试使用电子邮件“FOO@email.com”创建一个新用户,这对于 Rails 来说是完全有效的(默认情况下),INSERT 将被发送到数据库。如果您碰巧没有电子邮件的唯一索引,那么您会很高兴 - 行将毫无问题地插入。如果你碰巧有一个唯一索引,那么就会抛出异常。

好的。 Rails 说:由于您的数据库具有不区分大小写的排序规则,因此执行不区分大小写的唯一性验证。这是怎么做到的?它告诉您可以通过在特定属性验证器上设置“:case_sensitive => false”来覆盖默认的唯一性比较敏感度。在验证时,它会创建以下 SQL:

SELECT 1 FROM `Users` WHERE (LOWER(`Users`.`email`) = LOWER('FOO@email.com') LIMIT 1

这是数据库表 Users 上的灾难,您设计为在电子邮件字段上具有唯一索引,因为它不使用索引,所以进行全表扫描。

我现在看到 SQL 中的 LOWER 函数是由 ActiveRecordUniquenessValidator 插入的(文件 uniqueness.rb,模块 ActiveRecord,模块 ValidationsUniquenessValidator)。这是执行此操作的代码片段:

if value.nil? || (options[:case_sensitive] || !column.text?)
sql = "#{sql_attribute} #{operator}"
else
sql = "LOWER(#{sql_attribute}) = LOWER(?)"
end

所以问题转到 Rails/ActiveRecord 而不是 MySQL Adapter。

问题:有没有办法告诉 Rails 将关于唯一性验证区分大小写的要求传递给 MySQL 适配器,而不是“聪明”地改变查询?或者为了澄清而改写的问题:是否有另一种方法可以对属性实现唯一性验证(请小心......我不是在谈论电子邮件,只是以电子邮件为例)关闭区分大小写并生成将在相应列上使用简单唯一索引的查询?

这两个问题是等价的。我希望现在,我让自己更清楚,以便得到更准确的答案。

最佳答案

验证唯一性而不考虑大小写

如果你想坚持以大写或小写形式存储电子邮件,那么你可以使用以下内容来强制唯一性而不考虑大小写:

validates_uniqueness_of :email, case_sensitive: false

(另见这个问题: Rails "validates_uniqueness_of" Case Sensitivity )

完全删除大小写问题

与其进行不区分大小写的匹配,不如在验证之前将电子邮件小写(因此也是):

before_validation {self.email = email.downcase}

由于大小写与电子邮件无关,这也将简化您所做的一切,并将阻止您将来可能进行的任何比较或数据库搜索

关于mysql - 如何在不区分大小写的情况下指示 Rails 在唯一性验证上生成正确的 SQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7713752/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com