根据用户名+整数生成唯一的登录字符串失败,为什么?

时间:2017-06-07 21:14:28

标签: ruby-on-rails postgresql unique race-condition

我们在Ruby on Rails 4.2项目中使用此代码来生成唯一的用户名。下面的方法是User类的实例方法,并接收名称字符串,如果需要避免冲突,则附加一个整数。然后它返回一个唯一的登录名,例如用于像

self.login = self.generate_unique_sane_login(self.name)

在before_save挂钩或控制器中。特别是,在注册后创建新用户实例时会调用此方法。

然而,偶尔这个功能失败了。此方法返回已存在的登录名,然后数据库驱动程序抛出唯一性违规异常(在本例中为Postgres),并且应用程序抛出HTTP / 1.1 500.或者它甚至没有这样做,我们在数据库中有几个重复项这绝对是使用此代码创建的,但不会再次加载验证。那些用户无法编辑他们的个人资料。

当发生这种情况时,我们没有在我们的日志中看到多个同时(或几乎同时)的用户注册尝试,因此我认为这不是竞争条件问题。

所以:为什么会这样?我错过了什么吗?什么是生成唯一用户登录字符串的更好的解决方案?

 def self.generate_unique_sane_login(l)
    l = l.gsub(/\@.*$/, '')
    l = l.gsub(/[^A-Za-z0-9äöüÄÖÜß]/, '_')
    c = 1
    login = l
    conflicting_logins = self.where("LOWER(login) = LOWER(?)", login)
    until conflicting_logins.empty?
      login = "#{l}#{c}"
      conflicting_logins = self.where("LOWER(login) = LOWER(?)", login)
      c = c+1
    end
    login
  end

评论的答案

感谢您的评论。这是我的答案。

  • 我们已经使用了唯一性验证器,并且由于某种原因它没有捕获这些重复项。其他重复项被捕获(也都在测试中被捕获),并且这些异常是不可重复的(这意味着如果我们注册相同的登录名,在十分钟之后它会突然发生异常)。
  • 我希望了解现有代码以重构整个身份验证过程,因此其他宝石或替换代码现在不是一个选项。
  • 使用随机值作为整数部分是一个想法,但使登录非常长,我想避免,因为它们是用户可见的。使用计数器应该工作,不应该吗?

0 个答案:

没有答案