Best way to create unique token in Rails ?

Best way to create unique token in Rails ?

Asked on January 7, 2019 in Ruby on Rails.
Add Comment


  • 5 Answer(s)

    Rails 4 & 3: 

    The Future reference, creating safe random token and ensuring it’s uniqueness for the model.

    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
    

    Note 1:  Replace begin…end..while with loop do…break unless…end  implementation might get removed in the future.

    Note 2: Rails 4 and concerns 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
    

     

    Answered on January 7, 2019.
    Add Comment

    Produces a 40 character alphanumeric in string: 

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

    Answered on January 7, 2019.
    Add Comment

    The  late response in order to avoid using a loop  can also call the method recursively. 

    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
    

    Answered on January 7, 2019.
    Add Comment

    — 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
    Answered on March 5, 2019.
    Add Comment

    — 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
    Answered on March 5, 2019.
    Add Comment


  • Your Answer

    By posting your answer, you agree to the privacy policy and terms of service.