I need to generate a unique six digit alpha-numeric code. To save in my database as voucher no: for every transaction.
Asked
Active
Viewed 5,965 times
5
-
2Why are you not simply auto-incrementing the code? They'd be numeric then. If you have too many codes (more than 6 digits), you can use a Base32 enoding of this number, e.g. – Jens May 06 '11 at 10:49
-
Possible duplicate? http://stackoverflow.com/questions/88311/how-best-to-generate-a-random-string-in-ruby – Teoulas May 06 '11 at 10:50
-
@Teoulas I don't think so. There's nothing in this question that states that the codes need to be (or appear) random. – Phrogz May 06 '11 at 17:26
6 Answers
3
I used this
require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,6]
How to generate a random string in Ruby This link was useful

Community
- 1
- 1

Amal Kumar S
- 15,555
- 19
- 56
- 88
-
1This is a very bad answer with high probability of collision. With 1 million iterations there are 767 **thousand** collisions on 215 thousand keys. Bumping the random number from `10000` to `10000000` reduces the collisions to "only" 31,000 out of 1,000,000, but any collisions is still bad. This is true whether Time.now is always the same or if it returns a new value each call (e.g. no more than one transaction per second). – Phrogz May 06 '11 at 17:25
-
In normal case this an acceptable one. Is there any other way for this. – rubyprince May 11 '11 at 10:20
0
A better way is to let the database handle the ids(incrementing). But if you insisting on generating them your self, you can use a random generator to generate an code, check it against db for uniqueness. then either accept or regenerate

Shaunak
- 17,377
- 5
- 53
- 84
-
This is a bad idea in theory as you start to fill up the available namespace, since your chance of collisions increases and in the extreme you may end up stuck in a loop of regenerating for a very long time before you find a free key. – Phrogz May 06 '11 at 16:57
0
I'd use the database to generate unique keys, but if you insist on doing it the hard way:
class AlnumKey
def initialize
@chars = ('0' .. '9').to_a + ('a' .. 'z').to_a
end
def to_int(key)
i = 0
key.each_char do |ch|
i = i * @chars.length + @chars.index(ch)
end
i
end
def to_key(i)
s = ""
while i > 0
s += @chars[i % @chars.length]
i /= @chars.length
end
s.reverse
end
def next_key(last_key)
to_key(to_int(last_key) + 1)
end
end
al = AlnumKey.new
puts al.next_key("ab")
puts al.next_key("1")
puts al.next_key("zz")
Of course, you'll have to store your current key somewhere, and this is in no way thread / multisession-safe etc.

Frank Schmitt
- 30,195
- 12
- 73
- 107
0
With the following restrictions:
- Valid only until 2038-12-24 00:40:35 UTC
- Generates no more than once within a second
you can use this simple code:
Time.now.to_i.to_s(36)
# => "lks3bn"

sawa
- 165,429
- 45
- 277
- 381
-
2
-
-
@Zabba That will cause a problem, but I assumed it will not be so frequent. In that case, the system will have to be down for maintenance for the time span that equals the difference between the new and the old time zones. It will be less than a day, at worst. If the new time zone goes ahead, the system does not have to be down. – sawa May 06 '11 at 22:22
0
class IDSequence
attr_reader :current
def initialize(start=0,digits=6,base=36)
@id, @chars, @base = start, digits, base
end
def next
s = (@id+=1).to_s(@base)
@current = "0"*(@chars-s.length) << s
end
end
id = IDSequence.new
1234.times{ id.next }
puts id.current
#=> 0000ya
puts id.next
#=> 0000yb
9876543.times{ id.next }
puts id.current
#=> 05vpqq

Phrogz
- 296,393
- 112
- 651
- 745
0
This would eleviate the time collision issue by getting the milli seconds
(Time.now.to_f*1000.0).to_i

Nath
- 6,774
- 2
- 28
- 22