How to generate a unique string that does not collide with ruby?

Question: Question:

When deciding the file name of the file uploaded by the user, I came up with a method of issuing an ID from the current time (milliseconds) so that the file names do not conflict.
After trying various things, the following code was completed, but since I just converted the current time value to a 62-ary number, the first character of the file is fixed at almost p2 like "p2dhXa6" and "p2d9Wco".

You can leave it as it is, but is there a way to generate an ID that is unique, visually random, and has a shorter string length, using the characters available in the filename?

Current code

def uniqid()
  def dec62(num)
    table = [('0'..'9'),('a'..'z'),('A'..'Z')].map{|c| c.to_a }.flatten
    num > 61 ? dec62(num/62)+table[num%62] : table[num%62]
  end
  dec62(Time.now.instance_eval { self.to_i * 1000 + (usec/1000) })
end

Answer: Answer:

SecureRandom

I think it's better to use SecureRandom. (I personally like SecureRandom.uuid because it's easy to see that it was randomly generated.)

require "securerandom"

SecureRandom.hex
# => "3366ab379a65448704fa7c7cab4b0843"
SecureRandom.hex(32)
# => "4ab79521bf6712c1737b55f8393816b00996de29bed69257c5f6635bea899f9a"
SecureRandom.uuid
# => "d1d145ae-2e1e-4d5f-8f0b-e962c47624e0"
SecureRandom.urlsafe_base64
# => "B7Yj6QUYaYtbM7gflqEbaQ"
SecureRandom.urlsafe_base64(8)
# => "8CBbCIhp8hA"

URL-safe base64 (RFC 3548) is also "safe" as a file name because only "-" and "_" ("=" when padding is included) are used in addition to alphanumericals.

Tempfile

Tempfile is also a good choice for the purpose of creating temporary files. However, the directory is fixed. (The directory depends on the system.)

require "tempfile"

Tempfile.new("moemoe")
# => #<File:/var/folders/sz/slkk1lv965lcpl8djdlq8qdc0000gn/T/moemoe20150124-19905-m2sbfw>

Serial number

Also, if you want to create a unique file name for saving, you can use serial numbers. For example, if you are using Ruby on Rails (ActiveRecord), it is a good idea to create a file name based on the model id . (To be precise, it may not be a serial number depending on the environment and operation contents, but it is guaranteed to be unique.)

class UserFile < ActiveRecord::Base
  FILE_STORE_DIR = Rails.root + "store/user_files"

  def filename
    FILE_STORE_DIR + self.id.to_s
  end
end
uf = UserFile.create
uf.filename
=> #<Pathname:/User/fate/rails/hoge/store/user_files/1>
Scroll to Top