lib/prefixed_ids.rb in prefixed_ids-1.0.1 vs lib/prefixed_ids.rb in prefixed_ids-1.2.0
- old
+ new
@@ -1,29 +1,89 @@
require "prefixed_ids/version"
require "prefixed_ids/engine"
+require "hashids"
+
module PrefixedIds
- MINIMUM_TOKEN_LENGTH = 24
+ class Error < StandardError; end
- class MinimumLengthError < StandardError; end
+ autoload :PrefixId, "prefixed_ids/prefix_id"
+ TOKEN = 123
+ DELIMITER = "_"
+
+ mattr_accessor :alphabet, default: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
+ mattr_accessor :minimum_length, default: 24
+
+ mattr_accessor :models, default: {}
+
+ def self.find(prefix_id)
+ prefix, _ = split_id(prefix_id)
+ models.fetch(prefix).find_by_prefix_id(prefix_id)
+ rescue KeyError
+ raise Error, "Unable to find model with prefix `#{prefix}`. Available prefixes are: #{models.keys.join(", ")}"
+ end
+
+ # Splits a prefixed ID into its prefix and ID
+ def self.split_id(prefix_id)
+ prefix, _, id = prefix_id.to_s.rpartition(DELIMITER)
+ [prefix, id]
+ end
+
+ # Adds `has_prefix_id` method
+ module Rails
+ extend ActiveSupport::Concern
+
+ included do
+ class_attribute :_prefix_id
+ end
+
+ class_methods do
+ def has_prefix_id(prefix, override_find: true, override_param: true, **options)
+ include Attribute
+ include Finder if override_find
+ include ToParam if override_param
+ self._prefix_id = PrefixId.new(self, prefix, **options)
+
+ # Register with PrefixedIds to support PrefixedIds#find
+ PrefixedIds.models[prefix.to_s] = self
+ end
+ end
+ end
+
+ # Included when a module uses `has_prefix_id`
module Attribute
extend ActiveSupport::Concern
- module ClassMethods
- def has_prefix_id(prefix, attribute: :prefix_id, length: MINIMUM_TOKEN_LENGTH)
- if length < MINIMUM_TOKEN_LENGTH
- raise MinimumLengthError, "Token requires a minimum length of #{MINIMUM_TOKEN_LENGTH} characters."
- end
+ class_methods do
+ def find_by_prefix_id(id)
+ find_by(id: _prefix_id.decode(id))
+ end
- # Load securerandom only when has_secure_token is used.
- require "active_support/core_ext/securerandom"
- define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_prefix_id(prefix, length: length) }
- before_create { send("#{attribute}=", self.class.generate_unique_prefix_id(prefix, length: length)) unless send("#{attribute}?") }
+ def find_by_prefix_id!(id)
+ find_by!(id: _prefix_id.decode(id))
end
+ end
- def generate_unique_prefix_id(prefix, length: MINIMUM_TOKEN_LENGTH)
- prefix.to_s + "_" + SecureRandom.base58(length)
+ def prefix_id
+ self.class._prefix_id.encode(id)
+ end
+ end
+
+ module Finder
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def find(*ids)
+ super(*ids.map { |id| _prefix_id.decode(id) })
end
+ end
+ end
+
+ module ToParam
+ extend ActiveSupport::Concern
+
+ def to_param
+ _prefix_id.encode(id)
end
end
end