I need to generate a unique number for my model, which is called Shipment.
The number must be in the following format:
- Two digits - current month
- Two digits - current year
- Six digits - just digits
For instance: 1114000001. 11 - current month. 14 - year. 0000001 - just six digits.
So. My idea is to use the counter for 6 digits. I want store it in database, then I can use the lock and ensure uniqueness. But then it is obvious that it is a potential bottleneck. Because each new shipment will wait in line to access to counter.
My question is: What better? Use counter or generate a random number, and query the database:
while Shipment.where(:id => supposedly_unique_number.).exists?
And one more question: Where do I store this Сounter? I need only one for whole application. Create standalone table for only one value?
UPDATE
I just realized that this check
Shipment.where(:id => supposedly_unique_number.).exists?
does not guarantee uniqueness. :)
So where better to store the counter? I will be glad to any of your suggestions.
UPDATE2
mu is too short, mentioned database sequence. And I can`t find understandable information how to use it. I would be grateful if someone explain to me how it works.
Rails 4, Ruby 2, PostgreSql.
There are a couple things you need to consider here:
ids will have leading zeros so they're not numbers, they're strings that contain digit characters.id.Using a string for the
idis a bit of work to keep ActiveRecord from thinking it owns you but not that bad. You need to create the table without the implicitidthatcreate_tableadds, add your ownid, and set it as the primary key by hand:Now we need to hook up a default value so that the database can generate our
ids. Getting the date prefix is a simple of matter of using theto_charSQL function to format the current time (now()):To create the suffix, we can use a sequence. A database sequence is just database object that returns incrementing numbers in a safe way in the presence of multiple database connections. First, create the sequence:
To get the next value from a sequence we use the
nextvalSQL function:and again use
to_charto format it:The linked document explains what the
FM000000format means. Combining those two parts of theidgives us a default value of:Note that
||is string concatenation in SQL. Wrapping that in anotherconnection.executelets us attach the default to theidcolumn:If you want to reset the counters at the beginning of each month (or when you get close to the six digit limit), you can use the
setvalSQL function.Finally, since you're using all kinds of things that ActiveRecord doesn't understand, you'll want to switch from
schema.rbtostructure.sqlfor managing your schema information. You can do this in your configs by setting:and you'll use
rake db:structure:dumpanddb:structure:loadinstead of the schema tasks.Putting all that together will give you a migration like this: