【问题标题】:generate unique username (omniauth + devise)生成唯一的用户名(omniauth + devise)
【发布时间】:2012-03-28 10:15:21
【问题描述】:

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

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

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

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

例如生成密码我有这个:

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

如果 facebook 用户在 facebook 中没有用户名,我如何为我的应用生成唯一的用户名?

谢谢

【问题讨论】:

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


    【解决方案1】:

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

    #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
    

    【讨论】:

    • while 循环不应该在末尾包含 num += 1 吗?
    • 非常感谢!很有帮助!
    【解决方案2】:

    您可以在@ 符号之前获取电子邮件的一部分并在那里添加诸如 user_id 之类的东西,或者只获取电子邮件本身。或者,您可以以某种方式将 fb 响应中的名字和姓氏结合起来。

    【讨论】:

    • 谢谢,能写个例子吗?谢谢@alony ;)。我曾想过:user.username = "user_#{user.id.to_s}"。我正在使用mongoid。我的 ID 是 "4f72ee7e1d41c87cb1000001" 类型。我不知道我的修复是否正确!
    • 我总是这样:user.username = user.email[/^[^@]*/],它看起来不错,但可能会重复。在你的情况下,你可以这样做:user.username = "#{user.email[/^[^@]*/]}_#{user.id.to_s[0..5]}" - 取前 6 个只是不要让它太长:)
    • 谢谢它对我来说很好用:D。但是使用 0..5 它可能会重复吗?谢谢。
    • 是的,有可能,但是没有多少机会让 2 个人拥有相同的电子邮件名称和相同的前 6 个 ID 符号 :) 无论如何,这取决于你,使用整个 id 就可以了跨度>
    • 谢谢。我不想在应用程序中出现问题,所以我认为我将使用完整 ID 进行部署。它更有效但更丑陋:(。谢谢@alony
    【解决方案3】:

    这是我如何使用名字和姓氏字段组合创建登录。欢迎对此代码进行改进。

     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
    

    【讨论】:

    • 嘿戴夫,你能帮我解决这个问题吗?我尝试将此添加到我的用户模型中,但出现错误:Mysql2::Error: Unknown column 'users.login' in 'where clause': SELECT COUNT(*) FROM users WHERE users.@987654325 @ = 'bobweir'
    • 我也尝试了一个更简化的版本,如果你愿意,可以在这里查看我的帖子:stackoverflow.com/questions/30793011/…
    • @thesowismine 您是否在迁移文件中为用户表添加了一个名为“login”的列。添加它将解决您的错误。 :)
    • 我不久前就想通了,是的,就是这样!我只是感到困惑,因为我认为这是一种方法...感谢您发布此内容!
    【解决方案4】:

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

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

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

    【讨论】:

      【解决方案5】:

      这是我用于 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
      

      【讨论】:

        【解决方案6】:

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

          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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-11-03
          • 2012-02-01
          • 2012-11-06
          • 1970-01-01
          • 2022-11-13
          • 1970-01-01
          • 2014-08-19
          • 1970-01-01
          相关资源
          最近更新 更多