在我正在开发的Ruby on Rails应用程序中,我允许用户上传文件,并希望为这些文件提供一个简短的随机字母数字名称。 (例如'g7jf8'或'3bp76')。这样做的最佳方式是什么?
我想从原始文件名和时间戳生成哈希/加密字符串。然后查询数据库以仔细检查它不存在。如果是,请生成另一个并重复。
我用这种方法看到的问题是,如果重复字符串有很高的可用性,它可能会增加很多数据库负载。
答案 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"