Module: ConcernsOnRails::Models::Tokenizable
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/concerns_on_rails/models/tokenizable.rb
Overview
Generates and manages security tokens (API keys, invite codes, share links).
class User < ApplicationRecord
include ConcernsOnRails::Tokenizable
tokenizable_by :api_token # 32-char URL-safe
tokenizable_by :reset_password_token, length: 24
tokenizable_by :invite_code, type: :alphanumeric, length: 8
end
user = User.create! # tokens auto-generated on create
user.regenerate_api_token! # new value, persisted
user.revoke_api_token! # sets the column to nil
user.api_token? # true if present
User.find_by_api_token(token) # Rails default
User.authenticate_by_api_token(token) # timing-safe lookup, returns record or nil
Unlike Hashable, one model can declare multiple token fields, generation is URL-safe by default, and ‘assign_tokenizable_value` retries on uniqueness collisions before insert (best-effort; pair with a unique DB index).
Constant Summary collapse
- VALID_TYPES =
%i[urlsafe hex alphanumeric numeric].freeze
- ALPHANUMERIC_ALPHABET =
(("A".."Z").to_a + ("a".."z").to_a + ("0".."9").to_a).freeze
- NUMERIC_ALPHABET =
("0".."9").to_a.freeze
- MAX_GENERATION_ATTEMPTS =
10
Instance Method Summary collapse
-
#assign_tokenizable_value(field) ⇒ Object
Assigns the generated value only when blank, so callers can pass an explicit one.
Instance Method Details
#assign_tokenizable_value(field) ⇒ Object
Assigns the generated value only when blank, so callers can pass an explicit one. Retries up to MAX_GENERATION_ATTEMPTS times if the in-Ruby uniqueness check hits a collision — useful for short codes; a unique DB index is still the real guarantee.
123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/concerns_on_rails/models/tokenizable.rb', line 123 def assign_tokenizable_value(field) return if self[field].present? MAX_GENERATION_ATTEMPTS.times do candidate = self.class.generate_tokenizable_value(field) unless self.class.unscoped.exists?(field => candidate) self[field] = candidate return end end raise "ConcernsOnRails::Models::Tokenizable: could not generate a unique value for '#{field}' " \ "after #{MAX_GENERATION_ATTEMPTS} attempts — consider a longer length or a larger alphabet" end |