module Bullet class Association class <\n" end str end def bad_associations_str(bad_associations) puts bad_associations.inspect bad_associations.to_a.collect{|klazz, associations| klazz_associations_str(klazz, associations)}.join('\\n') end def klazz_associations_str(klazz, associations) "model: #{klazz} => associations: [#{associations.join(', ')}]" end def associations_str(associations) ":include => #{associations.map{|a| a.to_sym unless a.is_a? Hash}.inspect}" end def log_bad_associations(path) if @@logger unused_preload_associations.each do |klazz, associations| @@logger.info "Unused preload associations: PATH_INFO: #{path}; " + klazz_associations_str(klazz, associations) + "\n Remove from your finder: " + associations_str(associations) end unpreload_associations.each do |klazz, associations| @@logger.info "N+1 Query: PATH_INFO: #{path}; " + klazz_associations_str(klazz, associations) + "\n Add to your finder: " + associations_str(associations) end callers.each do |c| @@logger.info "N+1 Query: method call stack: \n" + c.join("\n") end @@logger_file.flush end end def has_klazz_association(klazz) !klazz_associations[klazz].nil? and klazz_associations.keys.include?(klazz) end def define_association(klazz, associations) # puts "define association, #{klazz} => #{associations}" add_klazz_associations(klazz, associations) end def call_association(object, associations) # puts "call association, #{object} => #{associations}" if unpreload_associations?(object, associations) add_unpreload_associations(object.class, associations) add_call_object_associations(object, associations) caller_in_project end end def unpreload_associations?(object, associations) klazz = object.class (!possible_objects[klazz].nil? and possible_objects[klazz].include?(object)) and (impossible_objects[klazz].nil? or !impossible_objects[klazz].include?(object)) and (object_associations[object].nil? or !object_associations[object].include?(associations)) end def add_unpreload_associations(klazz, associations) # puts "add unpreload associations, #{klazz} => #{associations.inspect}" unpreload_associations[klazz] ||= [] unpreload_associations[klazz] << associations unpreload_associations[klazz].uniq! end def add_unused_preload_associations(klazz, associations) # puts "add unused preload associations, #{object} => #{associations.inspect}" unused_preload_associations[klazz] ||= [] unused_preload_associations[klazz] << associations unused_preload_associations[klazz].flatten!.uniq! end def add_association(object, associations) # puts "add associations, #{object} => #{associations.inspect}" object_associations[object] ||= [] object_associations[object] << associations end def add_call_object_associations(object, associations) # puts "add call object associations, #{object} => #{associations.inspect}" call_object_associations[object] ||= [] call_object_associations[object] << associations end def add_possible_objects(objects) # puts "add possible objects, #{objects.inspect}" klazz= objects.first.class possible_objects[klazz] ||= [] possible_objects[klazz] << objects possible_objects[klazz].flatten!.uniq! end def add_impossible_object(object) # puts "add impossible object, #{object}" klazz = object.class impossible_objects[klazz] ||= [] impossible_objects[klazz] << object end def add_klazz_associations(klazz, associations) # puts "define associations, #{klazz} => #{associations.inspect}" klazz_associations[klazz] ||= [] klazz_associations[klazz] << associations end def unpreload_associations @@unpreload_associations ||= {} end def unused_preload_associations @@unused_preload_associations ||= {} end def object_associations @@object_associations ||= {} end def call_object_associations @@call_object_associations ||= {} end def possible_objects @@possible_objects ||= {} end def impossible_objects @@impossible_objects ||= {} end def klazz_associations @@klazz_associations ||= {} end VENDOR_ROOT = File.join(RAILS_ROOT, 'vendor') def caller_in_project callers << caller.select {|c| c =~ /#{RAILS_ROOT}/}.reject {|c| c =~ /#{VENDOR_ROOT}/} callers.uniq! end def callers @@callers ||= [] end end end end