Tutorial :How to make model IDs in Rails unpredictable and random


I'm writing a rails app that, by its nature, CANNOT require users to register, and thus cannot use authentication as the usual means to protect records. (I know, I know...) User information here is limited to email addresses. So I do need a way to make my model IDs unpredictable so that other IDs cannot be easily guessed. (I know, I know...)

I have tried using plugins like uuidtools to randomize ids as records are created, like so:

require 'uuidtools'  class Post < ActiveRecord::Base    def before_create()     self.id = OpenSSL::Digest.SHA1.hexdigest(UUID.timestamp_create())    end   end   

...This looks good at first, but funny things happen. ActiveRecord sometimes tries to insert a 0 value into the id and I get errors such as 'can't find Post with id=0' etc...

I've run out of ideas. Can anyone help? Thanks.


In your model, do this:

before_create :randomize_id    ...    private  def randomize_id    begin      self.id = SecureRandom.random_number(1_000_000)    end while Model.where(id: self.id).exists?  end  


Best way is to use SecureRandom.uuid that generates a V4 UUID (Universally Unique IDentifier).

It is virtually completely random and unique (collision probability is something like one over tens of trillions) : https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29

This should do the job :

class Post < ActiveRecord::Base   before_create :generate_random_id     private    def generate_random_id     self.id = SecureRandom.uuid   end   end  

Or if you are using Rails >= 4 and PostgreSQL, you can have it generating them for you :

create_table :posts, id: :uuid do |t|    ...  end  


There's a plugin that should do what you want:


(All apologies to the SO censors for not pasting in the entire article. In my defense, it's loaded with links and formatting that would require quite a bit of effort to replicate. Not to mention that we'd be robbing the page's author of traffic and potential revenue.)


The thing that is going wrong here is that self.id requires an int and OpenSSL::Digest.SHA1.hexdigest(UUID.timestamp_create()) returns a string with non-numeric characters which would lead to the value '0' being actually stored in the database


An alternative is to generate a token or checksum or whatever in a second column during record creation, and in all cases your controllers query for an object, use Model.find_by_id_and_token.

You'll then always generate URLs that contain and require both the id and token.

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »