trabajo-afectivo/app/models/application_model/can_lookup.rb

88 lines
2.4 KiB
Ruby
Raw Normal View History

# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
module ApplicationModel::CanLookup
extend ActiveSupport::Concern
class_methods do
=begin
lookup model from cache (if exists) or retrieve it from db, id, name, login or email possible
result = Model.lookup(id: 123)
result = Model.lookup(name: 'some name')
result = Model.lookup(login: 'some login')
result = Model.lookup(email: 'some login')
returns
result = model # with all attributes
=end
2018-07-04 12:57:10 +00:00
def lookup(**attr)
raise ArgumentError, "Multiple lookup attributes given (#{attr.keys.join(', ')}), only support (#{lookup_keys.join(', ')})" if attr.many?
2018-07-04 12:57:10 +00:00
attr.transform_keys!(&:to_sym).slice!(*lookup_keys)
raise ArgumentError, "Valid lookup attribute required (#{lookup_keys.join(', ')})" if attr.empty?
2019-06-28 11:38:49 +00:00
cache_get(attr.values.first) || find_and_save_to_cache_by(attr)
2018-07-04 12:57:10 +00:00
end
=begin
return possible lookup keys for model
result = Model.lookup_keys
returns
[:id, :name] # or, for users: [:id, :login, :email]
=end
2018-07-04 12:57:10 +00:00
def lookup_keys
@lookup_keys ||= %i[id name login email number] & attribute_names.map(&:to_sym)
end
private
def find_and_save_to_cache_by(args)
attribute = args.keys.first
lookup_value = args.values.first.to_s
# rollbacks can invalidate cache entry
# therefore we don't write it
if ActiveRecord::Base.connection.transaction_open?
result = find_by(attribute => lookup_value)
# enforce case-sensitivity on MySQL
result = nil if !key_sensitive_match?(result, attribute, lookup_value)
else
# get the record via an `FOR UPDATE` DB lock inside of
# a transaction to ensure that we don't write obsolete
# data into the cache
transaction do
result = lock.find_by(attribute => lookup_value)
# enforce case-sensitivity on MySQL
if key_sensitive_match?(result, attribute, lookup_value)
# cache only if we got a key-sensitive match
cache_set(lookup_value, result)
else
# no key-sensitive match - no result
result = nil
end
end
end
result
2018-07-04 12:57:10 +00:00
end
def key_sensitive_match?(record, attribute, lookup_value)
return false if record.blank?
return true if type_for_attribute(attribute.to_s).type != :string
record[attribute] == lookup_value
end
end
end