Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何在Ruby中生成一个随机且唯一的字符串?_Ruby On Rails_Ruby_Ruby On Rails 3 - Fatal编程技术网

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

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,并使用保存在某处的常

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

我正在考虑从原始文件名和时间戳生成一个哈希/加密字符串。然后查询数据库,再次检查它是否不存在。如果是,则生成另一个并重复


我发现这种方法的问题是,如果重复字符串的概率很高,它可能会增加相当多的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