moduleActiveRecordclassPredicateBuilder# :nodoc:@handlers=[]autoload:RelationHandler,'active_record/relation/predicate_builder/relation_handler'autoload:ArrayHandler,'active_record/relation/predicate_builder/array_handler'defself.resolve_column_aliases(klass,hash)hash=hash.duphash.keys.grep(Symbol)do|key|ifklass.attribute_alias?keyhash[klass.attribute_alias(key)]=hash.deletekeyendendhashenddefself.build_from_hash(klass,attributes,default_table)queries=[]attributes.eachdo|column,value|table=default_tableifvalue.is_a?(Hash)ifvalue.empty?queries<<'1=0'elsetable=Arel::Table.new(column,default_table.engine)association=klass._reflect_on_association(column)value.eachdo|k,v|queries.concatexpand(association&&association.klass,table,k,v)endendelsecolumn=column.to_sifcolumn.include?('.')table_name,column=column.split('.',2)table=Arel::Table.new(table_name,default_table.engine)endqueries.concatexpand(klass,table,column,value)endendqueriesenddefself.expand(klass,table,column,value)queries=[]# Find the foreign key when using queries such as:# Post.where(author: author)## For polymorphic relationships, find the foreign key and type:# PriceEstimate.where(estimate_of: treasure)ifklass&&reflection=klass._reflect_on_association(column)ifreflection.polymorphic?&&base_class=polymorphic_base_class_from_value(value)queries<<build(table[reflection.foreign_type],base_class)endcolumn=reflection.foreign_keyendqueries<<build(table[column],value)queriesenddefself.polymorphic_base_class_from_value(value)casevaluewhenRelationvalue.klass.base_classwhenArrayval=value.compact.firstval.class.base_classifval.is_a?(Base)whenBasevalue.class.base_classendenddefself.references(attributes)attributes.mapdo|key,value|ifvalue.is_a?(Hash)keyelsekey=key.to_skey.split('.').firstifkey.include?('.')endend.compactend# Define how a class is converted to Arel nodes when passed to +where+.# The handler can be any object that responds to +call+, and will be used# for any value that +===+ the class given. For example:## MyCustomDateRange = Struct.new(:start, :end)# handler = proc do |column, range|# Arel::Nodes::Between.new(column,# Arel::Nodes::And.new([range.start, range.end])# )# end# ActiveRecord::PredicateBuilder.register_handler(MyCustomDateRange, handler)defself.register_handler(klass,handler)@handlers.unshift([klass,handler])endregister_handler(BasicObject,->(attribute,value){attribute.eq(value)})# FIXME: I think we need to deprecate this behaviorregister_handler(Class,->(attribute,value){attribute.eq(value.name)})register_handler(Base,->(attribute,value){attribute.eq(value.id)})register_handler(Range,->(attribute,value){attribute.between(value)})register_handler(Relation,RelationHandler.new)register_handler(Array,ArrayHandler.new)defself.build(attribute,value)handler_for(value).call(attribute,value)endprivate_class_method:builddefself.handler_for(object)@handlers.detect{|klass,_|klass===object}.lastendprivate_class_method:handler_forendend