Hassen
Hassen

Reputation: 7654

Does SecureRandom generates a unique string or do I have to check?

I'm attributing a unique code to each created item, to use in the URL. I do this during the item creation in the model:

class Item < ActiveRecord::Base
  before_create { self.code = SecureRandom.urlsafe_base64 }
end

But I don't know if the generated code is really unique. Do I have to check the uniqueness during the creation, but this can take unnecessary time and resources if the Items table grows:

before_create :generate_unique_code

def generate_unique_code
  loop do
    code = SecureRandom.urlsafe_base64
    unless Item.where(:code => code).any?
      self.code = code
      break
    end
  end
end

Can I trust the uniqueness of SecureRandom.urlsafe_base64 and skip the check?

Upvotes: 1

Views: 1797

Answers (3)

rxing
rxing

Reputation: 373

Rails master branch includes one new module related to this. https://github.com/rails/rails/blob/master/activerecord/lib/active_record/secure_token.rb

Another solution you can reference.

Generating unique token on the fly with Rails

Upvotes: 0

sawa
sawa

Reputation: 168101

In order for it to be unique, it either has to (i) be following a rule that makes it never hit a previously generated output (such as by calling a one-to-one function on the time it was called, which only works under single thread), which makes it non-random, or (ii) keep a record of all previously generated outputs somewhere, which cannot be the case, and which also makes it non-random. In either case, you should be able to tell that is cannot be unique.

However, mathematics and engineering are different. Even if it is not unique, you can regard it as de facto unique. That is what programmers do.

Upvotes: 1

Simone Carletti
Simone Carletti

Reputation: 176402

Nothing is completely random in a computer generated string. Technically, there is a very low, remote possibility that two strings may be the same.

This is even more true in a highly concurrent system. If that's not the case, what you can do is to simply add an unique constraint (aka an unique index) at the database level. In this way, in the remote event that two strings will be equal, the database will reject the second one.

It's likely you will have an index on that field in any case if you need to use it for a query, therefore it should not add any unreasonable overhead.

As a side note, SecureRandom is a Ruby library, not a Rails library.

Upvotes: 1

Related Questions