In a Ruby on Rails app I am working on I allow users to upload files and want to give these files a short, random alphanumeric name. (Eg 'g7jf8' or '3bp76'). What is the best way to do this?
在我正在开发的Ruby on Rails应用程序中,我允许用户上传文件,并希望为这些文件提供一个简短的随机字母数字名称。 (例如'g7jf8'或'3bp76')。做这个的最好方式是什么?
I sas thinking of generating a hash / encrypted string from the original filename and timestamp. Then query the database to double check it doesnt exist. If it does, generate another and repeat.
我想从原始文件名和时间戳生成哈希/加密字符串。然后查询数据库以仔细检查它不存在。如果是,请生成另一个并重复。
The issue i see with this approach is if there is high propability of duplicate strings, it could add quite a lote of datbase load.
我用这种方法看到的问题是,如果重复字符串有很高的可用性,它可能会增加相当多的数据库负载。
7 个解决方案
#1
9
I use this :)
我用这个:)
def generate_token(column, length = 64)
begin
self[column] = SecureRandom.urlsafe_base64 length
end while Model.exists?(column => self[column])
end
Replace Model
by your model name
按型号名称替换型号
#2
8
SecureRandom.uuid
Will give you a globally unique String. http://en.m.wikipedia.org/wiki/Universally_unique_identifier
会给你一个全球唯一的字符串。 http://en.m.wikipedia.org/wiki/Universally_unique_identifier
SecureRandom.hex 32
Will give a random String, but it's algorithm is not optimised for uniqueness. Of course the chance of collision with 32 digits, assuming true randomness, is basically theoretical. You could make 1 billion per second for 100 years and have only a 50% chance of a collision.
会给出一个随机的String,但它的算法并没有针对唯一性进行优化。当然,假设真正的随机性,与32位数碰撞的机会基本上是理论上的。你可以在100年内每秒赚10亿,并且只有50%的碰撞几率。
#3
5
Use Ruby's SecureRandom.hex function with optional number of character you wanted to generate.
使用Ruby的SecureRandom.hex函数和您想要生成的可选字符数。
#4
0
You can assign a unique id by incrementing it each time a new file is added, and convert that id into an encrypted string using OpenSSL::Cipher
with a constant key that you save somewhere.
您可以通过在每次添加新文件时将其递增来分配唯一ID,并使用OpenSSL :: Cipher将该id转换为加密字符串,并使用您保存在某处的常量键。
#5
0
If you end up generating a hex or numeric digest, you can keep the code shorter by representing the number as e.g. Base 62:
如果您最终生成十六进制或数字摘要,则可以通过将数字表示为例如数字来缩短代码。基地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
If it is important for you to restrict the character set used (for instance not have uppercase chars in file names), then this code can easily be adapted, provided you can find a way of feeding in a suitable random number.
如果限制使用的字符集很重要(例如文件名中没有大写字符),那么只要您能找到一种合适的随机数字方式,就可以轻松调整此代码。
If your file names are supposed to be semi-secure, you need to arrange that there are many more possible names than actual names in storage.
如果您的文件名应该是半安全的,则需要安排在存储中存在比实际名称更多的可能名称。
#6
0
This will always produce new uniq 40 size alpha-numeric string, because it has Time stamp also.
这将始终产生新的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
结束
Note: Replace Model by your model_name and column_name by any existing column of your model.
注意:由model_name和column_name替换模型的任何现有列的Model。
#7
-1
It looks like you actually need a unique filenames, right? Why not forget about complex solutions and simply use Time#nsec?
看起来你真的需要一个独特的文件名,对吧?为什么不忘记复杂的解决方案,只需使用Time#nsec?
t = Time.now #=> 2007-11-17 15:18:03 +0900
"%10.9f" % t.to_f #=> "1195280283.536151409"
#1
9
I use this :)
我用这个:)
def generate_token(column, length = 64)
begin
self[column] = SecureRandom.urlsafe_base64 length
end while Model.exists?(column => self[column])
end
Replace Model
by your model name
按型号名称替换型号
#2
8
SecureRandom.uuid
Will give you a globally unique String. http://en.m.wikipedia.org/wiki/Universally_unique_identifier
会给你一个全球唯一的字符串。 http://en.m.wikipedia.org/wiki/Universally_unique_identifier
SecureRandom.hex 32
Will give a random String, but it's algorithm is not optimised for uniqueness. Of course the chance of collision with 32 digits, assuming true randomness, is basically theoretical. You could make 1 billion per second for 100 years and have only a 50% chance of a collision.
会给出一个随机的String,但它的算法并没有针对唯一性进行优化。当然,假设真正的随机性,与32位数碰撞的机会基本上是理论上的。你可以在100年内每秒赚10亿,并且只有50%的碰撞几率。
#3
5
Use Ruby's SecureRandom.hex function with optional number of character you wanted to generate.
使用Ruby的SecureRandom.hex函数和您想要生成的可选字符数。
#4
0
You can assign a unique id by incrementing it each time a new file is added, and convert that id into an encrypted string using OpenSSL::Cipher
with a constant key that you save somewhere.
您可以通过在每次添加新文件时将其递增来分配唯一ID,并使用OpenSSL :: Cipher将该id转换为加密字符串,并使用您保存在某处的常量键。
#5
0
If you end up generating a hex or numeric digest, you can keep the code shorter by representing the number as e.g. Base 62:
如果您最终生成十六进制或数字摘要,则可以通过将数字表示为例如数字来缩短代码。基地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
If it is important for you to restrict the character set used (for instance not have uppercase chars in file names), then this code can easily be adapted, provided you can find a way of feeding in a suitable random number.
如果限制使用的字符集很重要(例如文件名中没有大写字符),那么只要您能找到一种合适的随机数字方式,就可以轻松调整此代码。
If your file names are supposed to be semi-secure, you need to arrange that there are many more possible names than actual names in storage.
如果您的文件名应该是半安全的,则需要安排在存储中存在比实际名称更多的可能名称。
#6
0
This will always produce new uniq 40 size alpha-numeric string, because it has Time stamp also.
这将始终产生新的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
结束
Note: Replace Model by your model_name and column_name by any existing column of your model.
注意:由model_name和column_name替换模型的任何现有列的Model。
#7
-1
It looks like you actually need a unique filenames, right? Why not forget about complex solutions and simply use Time#nsec?
看起来你真的需要一个独特的文件名,对吧?为什么不忘记复杂的解决方案,只需使用Time#nsec?
t = Time.now #=> 2007-11-17 15:18:03 +0900
"%10.9f" % t.to_f #=> "1195280283.536151409"