Facebook omniauth:确保唯一的用户名

时间:2016-12-03 16:18:50

标签: ruby-on-rails devise omniauth-facebook

我有一个带有devise + omniauth用户身份验证的应用。 在我的用户模型中,我想确保user.name是唯一的,这样我的应用程序中就没有重复的用户名。

环顾四周后,我想出了以下代码:

User.rb

  validates :name, presence: true, uniqueness: true, length: {minimum: 6, maximum: 30}

  def ensure_username_uniqueness
    uniqname = (self.name).dup     
    num = 1
    until(User.find_by(name: uniqname).nil?) do ## returns true, should be false ##
      uniqname = self.name+"-#{num}"    
      num += 1
    end    
    self.name = uniqname      
  end  

  private  

  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.provider = auth.provider
      user.uid = auth.uid        
      user.email = auth.info.email
      user.password = Devise.friendly_token[0,20]
      user.name = auth.info.name[0..29].downcase.gsub(" ", "-")
      user.ensure_username_uniqueness           
      user.remote_avatar_url = auth.info.image
      user.skip_confirmation!
    end
  end   

当我使用数据库中已存在的名称测试Facebook注册时,我被重定向到注册页面(意味着注册失败)。

我设置了binding.pry并注意到'until'循环没有被执行,因为它返回true(即使名称已经存在)。我似乎无法理解为什么循环不会被执行。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:0)

do

结束时您遗漏了until
until(User.find_by(name: uniqname).nil?) do

答案 1 :(得分:0)

这里的问题似乎是用户模型已被Devise中的先前操作“限制”到仅创建新用户。因此,在您的suresure_username_uniqueness()方法被调用时,User.find_by()并没有搜索整个数据库。相反,Devise添加了用于过滤结果的其他子句

使代码正常工作的一种快速解决方案是对用户User.unscopedUser.default_scoped进行操作,以便您的查询脱离当前范围并搜索所有个用户:

  def ensure_username_uniqueness
    uniqname = (self.name).dup     
    num = 1
    until(User.unscoped.find_by(name: uniqname).nil?) do
      uniqname = self.name+"-#{num}"    
      num += 1
    end    
    self.name = uniqname      
  end