我如何在Ruby中生成随机且唯一的字符串?

时间:2013-03-17 09:06:00

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

在我正在开发的Ruby on Rails应用程序中,我允许用户上传文件,并希望为这些文件提供一个简短的随机字母数字名称。 (例如'g7jf8'或'3bp76')。这样做的最佳方式是什么?

我想从原始文件名和时间戳生成哈希/加密字符串。然后查询数据库以仔细检查它不存在。如果是,请生成另一个并重复。

我用这种方法看到的问题是,如果重复字符串有很高的可用性,它可能会增加很多数据库负载。

7 个答案:

答案 0 :(得分:12)

我用这个:)

def generate_token(column, length = 64)
  begin
    self[column] = SecureRandom.urlsafe_base64 length
  end while Model.exists?(column => self[column])
end

Model替换为您的型号名称

答案 1 :(得分:10)

SecureRandom.uuid

将为您提供全局唯一的字符串。 http://en.m.wikipedia.org/wiki/Universally_unique_identifier

SecureRandom.hex 32

会给出一个随机字符串,但它的算法并未针对唯一性进行优化。当然,假设真正的随机性,与32位数碰撞的机会基本上是理论上的。你可以在100年内每秒赚10亿,并且只有50%的机会发生碰撞。

答案 2 :(得分:6)

使用Ruby的SecureRandom.hex函数和您想要生成的可选字符数。

答案 3 :(得分:1)

这将始终产生新的uniq 40大小的字母数字字符串,因为它也有时间戳。

loop do
  random_token = Digest::SHA1.hexdigest([Time.now, rand(111..999)].join)
  break random_token unless Model.exists?(column_name: random_token)
end

注意:您的model_name和column_name将模型替换为模型的任何现有列。

答案 4 :(得分:0)

您可以在每次添加新文件时通过递增来分配唯一ID,并使用OpenSSL::Cipher将该ID转换为加密字符串,并使用您保存在某处的常量键。

答案 5 :(得分:0)

如果您最终生成十六进制或数字摘要,则可以通过将数字表示为例如数字来缩短代码。基地62:

# This is a lightweight base62 encoding for Ruby integers.
B62CHARS = ('0'..'9').to_a + ('a'..'z').to_a + ('A'..'Z').to_a

def base62_string nbr
  b62 = ''
  while nbr > 0
    b62 << B62CHARS[nbr % 62]
    nbr /= 62
  end
  b62.reverse
end

如果限制使用的字符集很重要(例如文件名中没有大写字符),那么只要您能找到一种以合适的随机数输入的方式,就可以轻松调整此代码。 / p>

如果您的文件名应该是半安全的,则需要安排在存储中存在比实际名称更多的可能名称。

答案 6 :(得分:-1)

看起来你确实需要一个独特的文件名,对吧?为什么不忘记复杂的解决方案,只需使用Time#nsec

t = Time.now        #=> 2007-11-17 15:18:03 +0900
"%10.9f" % t.to_f   #=> "1195280283.536151409"