Ruby on rails 如何在Ruby中生成一个随机且唯一的字符串?
在我正在开发的RubyonRails应用程序中,我允许用户上传文件,并希望为这些文件提供一个简短、随机的字母数字名称。(例如“g7jf8”或“3bp76”)。最好的方法是什么 我正在考虑从原始文件名和时间戳生成一个哈希/加密字符串。然后查询数据库,再次检查它是否不存在。如果是,则生成另一个并重复Ruby on rails 如何在Ruby中生成一个随机且唯一的字符串?,ruby-on-rails,ruby,ruby-on-rails-3,Ruby On Rails,Ruby,Ruby On Rails 3,在我正在开发的RubyonRails应用程序中,我允许用户上传文件,并希望为这些文件提供一个简短、随机的字母数字名称。(例如“g7jf8”或“3bp76”)。最好的方法是什么 我正在考虑从原始文件名和时间戳生成一个哈希/加密字符串。然后查询数据库,再次检查它是否不存在。如果是,则生成另一个并重复 我发现这种方法的问题是,如果重复字符串的概率很高,它可能会增加相当多的datbase负载。使用Ruby函数,可以选择要生成的字符数。您可以通过每次添加新文件时增加id来分配唯一id,并使用保存在某处的常
我发现这种方法的问题是,如果重复字符串的概率很高,它可能会增加相当多的datbase负载。使用Ruby函数,可以选择要生成的字符数。您可以通过每次添加新文件时增加id来分配唯一id,并使用保存在某处的常量密钥将该id转换为加密字符串。如果最终生成十六进制或数字摘要,则可以通过将数字表示为例如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
#这是一种针对Ruby整数的轻量级base62编码。
B62CHARS=('0'..'9')。至_a+('a'..'z')。至_a+('a'..'z')。至_a
def base62_字符串编号
b62=''
当nbr>0时
b62
将为您提供一个全局唯一的字符串
将给出一个随机字符串,但其算法未针对唯一性进行优化。当然,假设真实的随机性,与32位数字发生冲突的可能性基本上是理论上的。你可以在100年内每秒赚10亿,而发生冲突的几率只有50%。看起来你实际上需要一个唯一的文件名,对吗?为什么不忘记复杂的解决方案,简单地使用它呢
我用这个:)
将模型
替换为模型名这将始终生成新的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
注意:将模型替换为模型名称,将列名称替换为模型的任何现有列。如果两个请求试图同时添加相同的名称,则还可能存在竞争条件(如果不可能)。数据库应该对该列具有唯一约束,并且您应该准备捕获ActiveRecord::RecordNotUnique
。检查“随机”名称是否有安全目的?如果没有,你有更多的选择。它不需要是安全的,但可以在URL中使用。谢谢你到目前为止的帮助。有很多想法需要尝试和研究。我最喜欢这个问题的答案可能是SecureRandom.urlsafe\u base64
。如果应用程序又大又忙,并且有几个独立的服务器,最终两个会同时处理一个文件并发生冲突。完全可以肯定的是,Concat nanoecs与服务器名冲突。在这一点上,我认为SecureRandom.uuid是一个更简单的解决方案。在我的例子中,您可以获得开箱即用的可排序列表。当然,这是一个品味的问题。这并没有产生任何独特的东西,而这正是OP所要求的。给定相同的nbr
,每次都将返回相同的字符串,并且需要传递一个大得离谱的数字才能返回任何有效大小的字符串。例如:>base62_string 999999999999999#=>“1V973MbJYWoT”
@Chrisbloom7:同意,这需要输入一个数字,我没有解释如何获取(但我在文本中提到这是必需的)。在Ruby中,生成一个大小合适的随机数非常简单:SecureRandom.random\u number(2**128)
。这种方法也适用于序列、散列等。事实上,它需要大量的输入来生成短字符串,这对于OP来说是非常可取的,他们要求使用短字符串
SecureRandom.hex 32
t = Time.now #=> 2007-11-17 15:18:03 +0900
"%10.9f" % t.to_f #=> "1195280283.536151409"
def generate_token(column, length = 64)
begin
self[column] = SecureRandom.urlsafe_base64 length
end while Model.exists?(column => self[column])
end
loop do
random_token = Digest::SHA1.hexdigest([Time.now, rand(111..999)].join)
break random_token unless Model.exists?(column_name: random_token)
end