Rails 3.验证电子邮件唯一性和区分大小写失败

时间:2011-06-21 08:10:54

标签: ruby-on-rails-3 validation

我正在开发Rails 3中的应用程序,并且在注册时我需要用户输入他们的电子邮件地址,我需要它是唯一且区分大小写的。即当MyEmail@yahoo.com已经存在于数据库中时,没有人能够使用myEmail@yahoo.com注册。

这是我的代码,它崩溃了应用程序:

validates :email, :presence => true, :uniqueness => true, :case_sensitive => true,
                      :format => {:with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i}

它出了什么问题?

5 个答案:

答案 0 :(得分:39)

请不要使用区分大小写!!!它将获取所有用户!所以如果你有100.000个用户。首先,它将使用LOWER(电子邮件)获取所有内容。这可能非常慢,并且不会在电子邮件中使用您的索引。

这是我刚刚在这个主题上发现的一篇文章:http://techblog.floorplanner.com/post/20528527222/case-insensitive-validates-uniqueness-of-slowness

我的建议是:运行查询以使所有电子邮件降级,并使之前的验证过滤器对邮件属性进行包装,这样您就不会在该列中包含任何大写字符。

User.update_all('email = LOWER(email)')
过滤前

before_validation :downcase_email

private

def downcase_email
  self.email = email.downcase if email.present?
end

答案 1 :(得分:32)

对于Rails 3类型的验证,您需要嵌套不区分大小写的块,如此

validates :email, :uniqueness => { :case_sensitive => false }

答案 2 :(得分:3)

我没有对已接受的答案发表评论的声誉,但是@medBo询问了Rails 4中的行为。作为参考,当使用Rails 4.2 + MySQL时,如果我指定

validates :username, uniqueness: { case_sensitive: false }

ActiveRecord执行此查询:

SELECT  1 AS one FROM `users` WHERE `users`.`username` = 'TEST_USER' LIMIT 1

在这种情况下,搜索不区分大小写。但是当我设置:

validates :username, uniqueness: { case_sensitive: false }

执行:

SELECT  1 AS one FROM `users` WHERE `users`.`username` = BINARY 'TEST_USER'

BINARY运算符ensures the search is case sensitive 没有获取所有用户,至少对于我的设置而言,case_sensitive标志不会遇到@Michael的性能问题Koper注意到早期版本的Rails。我无法评论ActiveRecord如何为其他数据库设置执行。

答案 3 :(得分:1)

我不确定是否可以使用该语法进行不区分大小写的验证(至少,我没有找到任何文档)。

你应该能够像这样验证不区分大小写的唯一性:

validates_uniqueness_of :email, :case_sensitive => false

如果没有关于崩溃的更多详细信息,我无能为力。

答案 4 :(得分:0)

你可以在你的模型中使用一个回调,比如 email 属性上的“before_validation”,让它像这样小写:

import math
import functools
import matplotlib.pyplot as plt
import numpy as np
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg


bgcolor = '#252525'

slider_moved = 0


def moved_event(n, key):
    global slider_moved
    slider_moved = n


class Interface(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent, bg=bgcolor)

        # Framing of the window
        self.l_frame = tk.Frame(self, bg=bgcolor)
        self.l_frame.grid(column=0)
        self.r_frame = tk.Frame(self, bg=bgcolor)
        self.r_frame.grid(column=1)
        self.graph1 = tk.Frame(self.r_frame, bg=bgcolor)
        self.graph2 = tk.Frame(self.r_frame, bg=bgcolor)

        self.slider_frame = []
        self.label = []
        self.entry = []
        self.slider = []

        self.elements = {"text": ["The initial body's semi-major axis", "The target body's semi-major axis", "The target body's period",
                                  "The parent's gravitational parameter", "Delta-v to perform the transfer"],
                         "color": ["green", "#1f77b4", "white", "white", "orange"]}

        for n in range(len(self.elements["text"])):
            slider_frame = tk.Frame(self.l_frame, bg=bgcolor)
            self.slider_frame.append(slider_frame)
            slider_frame.grid(pady=5)

            label = tk.Label(self.slider_frame[n], bg=bgcolor, text=self.elements["text"][n], font=("Arial", 10), fg='white')
            self.label.append(label)
            label.pack(anchor=tk.W)

            entry = tk.Entry(self.slider_frame[n], relief='flat', bg='grey', fg='black', validate="key")
            self.entry.append(entry)
            entry.pack(fill=tk.X)
            self.entry[n].bind("<Return>", functools.partial(self.set_slider, n))

            slider = tk.Scale(self.slider_frame[n], sliderrelief='flat', length=600, from_=1E-5, to=20, resolution=1E-5, orient=tk.HORIZONTAL,
                              bd=0, highlightbackground=bgcolor, troughcolor=bgcolor, bg=self.elements["color"][n], sliderlength=40, showvalue=0,
                              activebackground=self.elements["color"][n], command=functools.partial(self.write, n))
            self.slider.append(slider)
            slider.pack()
            self.slider[n].bind("<Button>", functools.partial(moved_event, n))

        self.slider[0].set(10)
        self.slider[1].set(5)
        self.slider[2].set(2)
        self.slider[1].config(to=40)
        self.slider[2].config(to=4)

    def write(self, slider_updated, value):
        self.entry[slider_updated].delete(0, tk.END)
        self.entry[slider_updated].insert(0, value)
        if slider_updated == slider_moved:
            if slider_updated == 0 or slider_updated == 2:
                self.slider[1].config(to=self.slider[0].get() * 4)
                self.slider[1].set(self.slider[0].get() / self.slider[2].get())
            if slider_updated == 1:
                self.slider[2].set(self.slider[0].get() / self.slider[1].get())

    def set_slider(self, n, key):
        self.slider[n].set(self.entry[n].get())
        moved_event(n, key)


if __name__ == "__main__":
    root = tk.Tk()
    root.title("Transfer orbit calculator")
    root.geometry("1280x720")
    root.config(bg=bgcolor)
    root.iconbitmap("956255-200.ico")
    Interface(root).pack(expand=True)
    root.mainloop()


这将使电子邮件输入小写,然后尝试不区分大小写的唯一性验证:

  before_validation { self.email = email.downcase }

有关回调的更多信息:这里是 ruby​​ 指南 https://guides.rubyonrails.org/active_record_callbacks.html