【问题标题】:Rails Active Record case insensitive findRails Active Record 不区分大小写的查找
【发布时间】:2012-07-05 16:45:57
【问题描述】:

虽然总的来说我喜欢在我的数据库中区分大小写,但有几次我觉得它很痛苦。 user_name 和 email 是我不想担心的字段的好例子——尤其是在搜索时。

在保存之前使用以下方式将字符串小写很容易:

before_save 做 self.email.downcase! 结束

这样,用户名和电子邮件始终以小写形式保存。但是 find_by_user_name 和 find_by_email 的最佳方法是什么?我当然可以记住总是将我传递给这些方法的字符串小写——但这似乎不是很干。

我曾考虑过覆盖 find_by_email 并在我缩减电子邮件后使用 super 调用原始邮件,但我没有任何运气来解决这个问题。

那么,最好的方法是什么?

PS 我不认为像这样的相关帖子 (how can I write a case-insensitive find_by_email for Rails 3) 试图解决同样的问题。此处带有“较低”的自定义 sql 对我来说是毫无意义的,因为我已经确保所有这些值都较低 - 它是现在进入的那个(可能来自用户输入它的表单),我需要小写。

【问题讨论】:

标签: ruby-on-rails-3 activerecord find


【解决方案1】:

它对我有用!谢谢,但要使用 lower(:xxx)。

Client.includes(:responsibles).where(["lower(name) || lower(contact) || cnpj || clients.rg || rg ILIKE ?", "%#{params[:search]} %"])

【讨论】:

    【解决方案2】:

    其中一个应该是好的:

    def self.find_by_lower_email(email)
      User.find_by_email(email.downcase)
    end
    # OR
    def self.find_by_email(email)
      User.find(:all, :conditions => ["email = lower(?)", email]) 
    end
    

    更新

    find_by_... 函数实际上是不存在的。当您调用其中之一时,ActiveRecord::Base 会在 method_missing 方法中捕获您的调用,并且如果名称格式正确(包含列名等),则会为该类创建适当的 find 方法。之后它就会存在。

    如果您有find_by_email,默认情况下会调用它。如果它调用super,那意味着你尝试调用ActiveRecord::Base.find_by_email,它不存在。 missing_method 捕获它,并创建(实际上覆盖您的)find_by_email 实现。这就是为什么在那里称呼 super 不好。如果您使用自己的实现来通过电子邮件查找,就像我在第二部分中所写的那样,那么它将非常有效。

    【讨论】:

    • 感谢 Matzi,我喜欢您的建议,我将实施第一个建议。只是好奇你会推荐创建这个新方法而不是覆盖 find_by_email 吗?对我来说,覆盖它似乎更好,因为调用 find_by_email 是很自然的——但我不确定如何。
    • 在 rails 2.0 中它是有缺陷的,当你调用 super 时,missing_method 覆盖了你的 find_by 函数,导致它只工作一次。我不知道它是否得到纠正,但安全总比抱歉好。如果您想调用 find_by_email,请使用我的第二个选项,无论如何应该可以。
    • 对不起,没有按照你写的最后一部分“如果你想调用 find_by_email,那么使用我的第二个选项......”。在你的第二个选项中,我不是还在打电话 find_by_lower_email 吗?
    • 我的意思是我的函数的两个部分是两个不同的实现。如果您调用函数 find_by_email,则可以使用第二个。
    • 太棒了。感谢您的修订。我知道了。我将实施第二个解决方案。
    【解决方案3】:

    使用 PostgreSQL,您可以:

    User.where("email ILIKE ?", email).first
    

    【讨论】:

    • 这是否容易受到 SQL 注入的攻击?
    • 为了清楚(对于未来的读者),问题中的版本不受 SQL 注入的影响。评论中的版本不是。
    • @Kevin 什么版本,Rails? PostgreSQL?
    • @evanrmurphy 似乎有一条旧评论已被删除,我指的是。
    • User.find_by 'email ILIKE ?', email 是 Rubocop 推荐的方式,使用 find_by 而不是 where.first。
    【解决方案4】:

    我做了这样的事情:

    def self.find_by_email(email)
      Member.find(:first, :conditions => ["lower(email) =?", email.downcase])
    end
    

    您可以就这是否正确进行辩论,但通常应该将电子邮件规范化到数据库中以防止需要这样做。

    编辑: 导轨 3:

    Member.where("lower(email) =?", email.downcase).first
    

    【讨论】:

    • 要么我错过了你的观点,要么你错过了我的问题的重点。我同意通常你应该在保存之前小写。如果您假设已完成,则不需要“lower(email)=?”部分,但您仍然需要 email.downcase 部分——因为电子邮件地址通常是由用户提供的,他们可能没有小写——这就是我的问题的重点。我相信 Matzi 的回答是正确的。
    • 那么你应该知道它在插入数据库时​​是否被小写。似乎 Matzi 的响应是一个很好的解决方案,但它假设电子邮件在数据库中是小写的,或者在传递到 find_by_email 方法时是小写的,我相信。他也将返回一个电子邮件数组,而 :first 将返回第一个响应作为实际的成员对象。没有?
    • 您在 :first 上提出了一个很好的观点。尽管假设电子邮件在解决方案中被小写,但我认为这是错误的,因为问题中特别指出了这一点。
    猜你喜欢
    • 2011-11-05
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多