13

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

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

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

4

7 回答 7

12

我用这个:)

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

替换Model为您的型号名称

于 2013-03-17T13:40:05.300 回答
10
SecureRandom.uuid

会给你一个全球唯一的字符串。http://en.m.wikipedia.org/wiki/Universally_unique_identifier

SecureRandom.hex 32

会给出一个随机字符串,但它的算法没有针对唯一性进行优化。当然,假设真正的随机性,与 32 位发生冲突的可能性基本上是理论上的。你可以每秒赚 10 亿美元,持续 100 年,但发生碰撞的几率只有 50%。

于 2013-03-17T10:23:38.530 回答
6

将 Ruby 的SecureRandom.hex函数与您想要生成的可选字符数一起使用。

于 2013-03-17T09:11:42.767 回答
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

注意:将模型替换为您的模型名称,将列名称替换为模型的任何现有列。

于 2017-08-22T06:42:29.847 回答
0

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

于 2013-03-17T09:16:13.077 回答
0

如果您最终生成一个十六进制或数字摘要,您可以通过将数字表示为例如 Base 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

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

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

于 2013-03-17T09:22:10.870 回答
0

看起来您实际上需要一个唯一的文件名,对吗?为什么不忘记复杂的解决方案并简单地使用Time#nsec

t = Time.now        #=> 2007-11-17 15:18:03 +0900
"%10.9f" % t.to_f   #=> "1195280283.536151409"
于 2013-03-17T10:49:12.247 回答