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



Question:

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.


Solution:1

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  


Solution:2

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  


Solution:3

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

http://codesnipers.com/?q=using-uuid-guid-as-primary-key-in-rails

(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.)


Solution:4

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


Solution:5

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
Previous
Next Post »