Как я могу создать случайную и уникальную строку в Ruby?

В приложении Ruby on Rails я работаю над тем, чтобы разрешить пользователям загружать файлы и хотеть дать этим файлам короткое, случайное буквенно-цифровое имя. (Например, 'g7jf8' или '3bp76'). Каков наилучший способ сделать это?

Я думал о создании хэш/зашифрованной строки из исходного имени файла и метки времени. Затем запросите базу данных, чтобы проверить, не существует. Если это так, создайте другое и повторите.

Проблема, которую я вижу при таком подходе, заключается в том, что существует высокая вероятность дублирования строк, она может добавить довольно большую нагрузку datbase.

Ответ 1

Я использую это:)

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

Замените Model на свое имя модели

Ответ 2

SecureRandom.uuid

Дает вам уникальную в мире String. http://en.m.wikipedia.org/wiki/Universally_unique_identifier

SecureRandom.hex 32

Дает случайный String, но алгоритм не оптимизирован для уникальности. Конечно, вероятность столкновения с 32 цифрами, предполагая истинную случайность, в основном теоретическая. Вы можете сделать 1 миллиард в секунду в течение 100 лет и иметь только 50% -ный шанс столкновения.

Ответ 3

Используйте функцию Ruby SecureRandom.hex с дополнительным количеством символов, которое вы хотели создать.

Ответ 4

Вы можете назначить уникальный идентификатор, увеличивая его каждый раз при добавлении нового файла и преобразовывая его в зашифрованную строку, используя OpenSSL::Cipher с постоянным ключом, который вы где-то сохраняете.

Ответ 5

Если вы закончите генерировать шестнадцатеричный или цифровой дайджест, вы можете сохранить код короче, указав номер, например. База 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

Если вам важно ограничить используемый набор символов (например, не иметь заглавных букв в именах файлов), тогда этот код можно легко адаптировать, если вы можете найти способ подачи подходящего случайного числа.

Если ваши имена файлов должны быть полузащищенными, вам необходимо учесть, что в хранилище имеется гораздо больше возможных имен, чем фактические имена.

Ответ 6

Это всегда будет производить новую альфа-цифровую строку размера 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)

конец

Примечание. Замените модель на имя модели и имя_каталога любым существующим столбцом вашей модели.

Ответ 7

Самый простой способ - использовать string_pattern gem https://github.com/MarioRuiz/string_pattern

Это будет генерировать 1000 уникальных строк от 6 до 20 символов, включая буквы, и заставить включать специальные символы и цифры

require 'string_pattern'
1000.times {
    puts :"6-20:L/$N/&".gen 
}

Ответ 8

Похоже, вам действительно нужны уникальные имена файлов, не так ли? Почему бы не забыть о сложных решениях и просто использовать Время # nsec?

t = Time.now        #=> 2007-11-17 15:18:03 +0900
"%10.9f" % t.to_f   #=> "1195280283.536151409"