Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to create unique token in Rails?

People also ask

What is Ruby on Rails token?

Each Ruby on Rails web application contains a secret token (usually stored in the file secret_token. rb). This token secret_token is used to sign cookies that the application sets. Without this, it's impossible to trust cookies that the browser sends, and hence difficult to rely on session based authentication.


-- Update --

As of January 9th, 2015. the solution is now implemented in Rails 5 ActiveRecord's secure token implementation.

-- Rails 4 & 3 --

Just for future reference, creating safe random token and ensuring it's uniqueness for the model (when using Ruby 1.9 and ActiveRecord):

class ModelName < ActiveRecord::Base

  before_create :generate_token

  protected

  def generate_token
    self.token = loop do
      random_token = SecureRandom.urlsafe_base64(nil, false)
      break random_token unless ModelName.exists?(token: random_token)
    end
  end

end

Edit:

@kain suggested, and I agreed, to replace begin...end..while with loop do...break unless...end in this answer because previous implementation might get removed in the future.

Edit 2:

With Rails 4 and concerns, I would recommend moving this to concern.

# app/models/model_name.rb
class ModelName < ActiveRecord::Base
  include Tokenable
end

# app/models/concerns/tokenable.rb
module Tokenable
  extend ActiveSupport::Concern

  included do
    before_create :generate_token
  end

  protected

  def generate_token
    self.token = loop do
      random_token = SecureRandom.urlsafe_base64(nil, false)
      break random_token unless self.class.exists?(token: random_token)
    end
  end
end

Ryan Bates uses a nice little bit of code in his Railscast on beta invitations. This produces a 40 character alphanumeric string.

Digest::SHA1.hexdigest([Time.now, rand].join)

This might be a late response but in order to avoid using a loop you can also call the method recursively. It looks and feels slightly cleaner to me.

class ModelName < ActiveRecord::Base

  before_create :generate_token

  protected

  def generate_token
    self.token = SecureRandom.urlsafe_base64
    generate_token if ModelName.exists?(token: self.token)
  end

end

There are some pretty slick ways of doing this demonstrated in this article:

https://web.archive.org/web/20121026000606/http://blog.logeek.fr/2009/7/2/creating-small-unique-tokens-in-ruby

My favorite listed is this:

rand(36**8).to_s(36)
=> "uur0cj2h"

If you want something that will be unique you can use something like this:

string = (Digest::MD5.hexdigest "#{ActiveSupport::SecureRandom.hex(10)}-#{DateTime.now.to_s}")

however this will generate string of 32 characters.

There is however other way:

require 'base64'

def after_create
update_attributes!(:token => Base64::encode64(id.to_s))
end

for example for id like 10000, generated token would be like "MTAwMDA=" (and you can easily decode it for id, just make

Base64::decode64(string)

This may be helpful :

SecureRandom.base64(15).tr('+/=', '0aZ')

If you want to remove any special character than put in first argument '+/=' and any character put in second argument '0aZ' and 15 is the length here .

And if you want to remove the extra spaces and new line character than add the things like :

SecureRandom.base64(15).tr('+/=', '0aZ').strip.delete("\n")

Hope this will help to anybody.