danieldraper/hashids_uri

View on GitHub
lib/hashids_uri.rb

Summary

Maintainability
A
35 mins
Test Coverage
require 'hashids'
require 'active_record'

module ActiveRecord
  module HashidsUri
    def self.included(base)
      base.extend         ClassMethods
      base.send :include, InstanceMethods
    end

    module ClassMethods
      def has_hashids_uri(options = {})
        class_attribute :salt, :min_length

        self.salt = options.fetch(:salt, '')
        self.min_length = options.fetch(:min_length, 6)

        define_method(:hashid) { read_attribute(:hashid) || generate_hashid }
        after_create { update_attribute(:hashid, generate_hashid) unless hashid? }
      end

      def find_by_hash(hash)
        decoded_id = ::Hashids.new(
          self.salt,
          self.min_length
        ).decode(hash).first

        find(decoded_id)
      end

      def find(*args)
        id = args.first
        return super if args.count != 1 || (Integer(id) rescue false)
        find_by_hash(id).tap { |result| return result unless result.nil? }
        raise ActiveRecord::RecordNotFound, "cannot find record with hash id: #{id.inspect}"
      end
    end

    module InstanceMethods
      def salt
        self.class.salt
      end

      def min_length
        self.class.min_length
      end

      def generate_hashid
        ::Hashids.new(
          salt,
          min_length
        ).encode(id)
      end

      def to_param
        hashid
      end
    end
  end
end

ActiveRecord::Base.send(:include, ActiveRecord::HashidsUri)