Posted over 6 years ago. Visible to the public.

Generate unique random token.

We sometimes need unique and random tokens in our web apps. Here is how we typically build it.

class User < ActiveRecord::Base before_create :set_access_token private def set_access_token self.access_token = generate_token end def generate_token loop do token = SecureRandom.hex(10) break token unless User.where(access_token: token).exists? end end end

Rails 5 has added has_secure_token method to generate a random alphanumeric token for a given column.

class User < ApplicationRecord has_secure_token end

By default, Rails assumes that the attribute name is token. We can provide a different name as a parameter to has_secure_token if the attribute name is not token.

class User < ApplicationRecord has_secure_token :password_reset_token end >> user = >> => true >> user.password_reset_token => 'qjCbex522DfVEVd5ysUWppWQ'

The generated tokens are URL safe and are of fixed length strings. We can also generate migration for token similar to other data types.

rails g migration add_auth_token_to_user auth_token:token class AddAuthTokenToUser < ActiveRecord::Migration[5.0] def change add_column :users, :auth_token, :string add_index :users, :auth_token, unique: true end end

Notice that migration automatically adds index on the generated column with unique constraint. We can also generate a model with the token attribute.

rails g model Product access_token:token class CreateProducts < ActiveRecord::Migration[5.0] def change create_table :products do |t| t.string :access_token t.timestamps end add_index :products, :access_token, unique: true end end

Model generator also adds has_secure_token method to the model.

class Product < ApplicationRecord has_secure_token :access_token end

In order to regenerate tokens, we can simply call regenerate_#{token_attribute_name} which would regenerate the token and save it to its respective attribute.

>> user = User.first => <User id: 11, name: 'John', email: '', token: "jRMcN645BQyDr67yHR3qjsJF", password_reset_token: "qjCbex522DfVEVd5ysUWppWQ"> >> user.password_reset_token => "qjCbex522DfVEVd5ysUWppWQ" >> user.regenerate_password_reset_token => true >> user.password_reset_token => "tYYVjnCEd1LAXvmLCyyQFzbm"

It is possible to generate a race condition in the database while generating the tokens. So it is advisable to add a unique index in the database to deal with this unlikely scenario.

Owner of this card:

Alexander M
Last edit:
over 6 years ago
by Alexander M
Posted by Alexander M to Ruby and RoR knowledge base
This website uses short-lived cookies to improve usability.
Accept or learn more