生成唯一的用户名(omniauth + devise)

时间:2012-03-28 10:15:22

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

我有一个带有devise + omniauth用户身份验证的应用。

在我的模型中,我的应用中的用户名是唯一。我不想在我的应用中使用重复的用户名。

Facebook中的某些用户在其个人资料中没有定义的用户名。

如果用户没有在facebook中定义用户名,我想生成一个唯一的用户名。

例如,对于生成密码,我有这个:

:password => Devise.friendly_token[0,20]

如果Facebook用户在Facebook中没有用户名,我怎样才能为我的应用生成唯一的用户名?

谢谢

6 个答案:

答案 0 :(得分:11)

您可以创建一个很好的可读用户名(例如从电子邮件的第一部分生成),然后通过添加数字来确保它是唯一的。例如

#in User
def get_unique_login
  login_part = self.email.split("@").first
  new_login = login_part.dup 
  num = 2
  while(User.find_by_login(new_login).count > 0)
    new_login = "#{login_part}#{num}"
    num += 1
  end
  new_login
end

这里的一个问题是,有人可能会在你获得它并保存它之间将登录包装起来。所以,也许最好把它组合成一个before_create过滤器:

#in User
before_create :ensure_login_uniqueness

def ensure_login_uniqueness 
  if self.login.blank? || User.find_by_login(self.login).count > 0
    login_part = self.email.split("@").first
    new_login = login_part.dup 
    num = 2
    while(User.find_by_login(new_login).count > 0)
      new_login = "#{login_part}#{num}"
      num += 1
    end
    self.login = new_login
  end
end

答案 1 :(得分:2)

你可以在@符号之前接收电子邮件的一部分,并像user_id一样添加smth,或者只是接收电子邮件本身。或者你可以以某种方式结合fb响应中的名字和姓氏。

答案 2 :(得分:2)

以下是我使用名字和姓氏字段组合创建登录的方法。欢迎使用此代码的改进。

 before_create :ensure_login_uniqueness

  def ensure_login_uniqueness 
    if self.login.blank? 
      self.name = self.first_name + " " + self.last_name
      firstnamePart = self.first_name.downcase.strip.gsub(' ', '').gsub(/[^\w-]/, '')
      lastnamePart = self.last_name.downcase.strip.gsub(' ', '').gsub(/[^\w-]/, '') 
      login_part = firstnamePart+lastnamePart 
      new_login = login_part.dup 
      num = 1
      while(User.where(:login => new_login).count > 0)
        new_login = "#{login_part}#{num}"
        num += 1
      end
      self.login = new_login
    end
  end

答案 3 :(得分:1)

它对我不起作用,但改变了:

while(User.find_by_login(new_login).count > 0)

while(User.where(login: new_login).count > 0)

答案 4 :(得分:1)

这是我用于Facebook的方法

  def ensure_username_uniqueness
    self.username ||= self.email.split("@").first
    num = 2
    until(User.find_by(username: self.username).nil?)
      self.username = "#{username_part}#{num}"
      num += 1
    end
  end

  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.email = auth.info.email
      user.password = Devise.friendly_token[0,20]
      user.username = auth.info.name.downcase.gsub(" ", "")
      user.username = user.username[0..29] if user.username.length > 30
      user.ensure_username_uniqueness
    end
  end

答案 5 :(得分:0)

这是从“全名”生成“用户名”的方法

  def self.generate_username(full_name)
    generated = ActiveSupport::Inflector.transliterate(full_name) # change ñ => n
                            .downcase              # only lower case
                            .strip                 # remove spaces around the string
                            .gsub(/[^a-z]/, '_')   # any character that is not a letter or a number will be _
                            .gsub(/\A_+/, '')      # remove underscores at the beginning
                            .gsub(/_+\Z/, '')      # remove underscores at the end
                            .gsub(/_+/, '_')

    taken_usernames = User
                        .where("username LIKE ?", "#{generated}%")
                        .pluck(:username)

    # username if it's free
    return generated unless taken_usernames.include?(generated)

    count = 2
    while true
      # username_2, username_3...
      new_username = "#{generated}_#{count}"
      return new_username if ! taken_usernames.include?(new_username)
      count += 1
    end
  end