Skip to content

Instantly share code, notes, and snippets.

@TikiTDO
Last active August 29, 2015 14:08
Show Gist options
  • Save TikiTDO/bda28aa2bc387489e2af to your computer and use it in GitHub Desktop.
Save TikiTDO/bda28aa2bc387489e2af to your computer and use it in GitHub Desktop.
Fixes to make poly int type work with where requests
module PolymorphicIntegerWhere
class Railtie < Rails::Railtie
initializer "PolymorphicInteger.active_record" do
::PolymorphicIntegerType::Extensions::ClassMethods.class_eval do
prepend ForcePolymorphicInteger
end
::ActiveRecord::Associations::BelongsToPolymorphicAssociation.class_eval do
prepend InjectBelongsToPolymorphicAssociation
end
::ActiveRecord::PredicateBuilder.class_eval do
class << self
prepend InjectPredicateBuilder
end
end
end
end
module ForcePolymorphicInteger
force_poly = proc do |name, scope_or_options = nil, options = {}, &block|
# Organize scope and options
if scope_or_options.kind_of? Hash
options, scope = scope_or_options, nil
else
scope = scope_or_options
end
# Ensure polymorphic assoc are integer types
if (options[:polymorphic] || options[:as]) && (!options[:integer_type])
raise "Add [integer_type: true] to #{self.name}##{name} polymorphic association"
end
# Pass on control
super name, scope, options, &block
end
define_method :belongs_to, &force_poly
define_method :has_one, &force_poly
define_method :has_many, &force_poly
end
module InjectBelongsToPolymorphicAssociation
# Might not be necessary
# def klass
# return super
# if reflection.active_record < PolymorphicIntegerType::Extensions
# mapping = PolymorphicIntegerType::Mapping[reflection.name]
# type = mapping[owner[reflection.foreign_type]]
# type.presence && type.constantize
# else
# super
# end
# end
end
module InjectPredicateBuilder
# Overwrite code that builds the right ordinal of a polymorphic request.
# Caution: This also builds a lot of other things
def build(attribute, value)
ret = super
# Special handling for PolyInt classes
target_class = attribute.relation.engine
if target_class < PolymorphicIntegerType::Extensions
# Reset the polymorphic cache on file reload
if !@__poly_assoc_cache
@__poly_assoc_cache = {}
ActionDispatch::Reloader.to_prepare { @__poly_assoc_cache = {} }
end
# Generate the polymorphic cache to speed query generation
@__poly_assoc_cache[target_class] ||= target_class.reflections.map do |k, v|
if v.polymorphic? then [v.foreign_type, k] else [nil, nil] end
end.to_h
# Check if this request need poly int processing
poly_assoc_name = @__poly_assoc_cache[target_class][attribute.name]
if poly_assoc_name
poly_assoc_name = poly_assoc_name.to_sym
mapping = PolymorphicIntegerType::Mapping[poly_assoc_name]
result = (mapping||{ret.right => ret.right}).key ret.right
ret.right = result if result
end
end
# Done processing, return the result
ret
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment