module Bullet::ActiveRecord
Public Class Methods
enable()
click to toggle source
# File lib/bullet/active_record4.rb, line 5 def self.enable require 'active_record' ::ActiveRecord::Base.class_eval do class <<self alias_method :origin_find_by_sql, :find_by_sql def find_by_sql(sql, binds = []) result = origin_find_by_sql(sql, binds) if Bullet.start? if result.is_a? Array if result.size > 1 Bullet::Detector::NPlusOneQuery.add_possible_objects(result) Bullet::Detector::CounterCache.add_possible_objects(result) elsif result.size == 1 Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first) Bullet::Detector::CounterCache.add_impossible_object(result.first) end elsif result.is_a? ::ActiveRecord::Base Bullet::Detector::NPlusOneQuery.add_impossible_object(result) Bullet::Detector::CounterCache.add_impossible_object(result) end end result end end end ::ActiveRecord::Relation.class_eval do alias_method :origin_to_a, :to_a # if select a collection of objects, then these objects have possible to cause N+1 query. # if select only one object, then the only one object has impossible to cause N+1 query. def to_a records = origin_to_a if Bullet.start? if records.size > 1 Bullet::Detector::NPlusOneQuery.add_possible_objects(records) Bullet::Detector::CounterCache.add_possible_objects(records) elsif records.size == 1 Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first) Bullet::Detector::CounterCache.add_impossible_object(records.first) end end records end end ::ActiveRecord::Persistence.class_eval do def save_with_bullet(*args, &proc) was_new_record = new_record? save_without_bullet(*args, &proc).tap do |result| Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record end end alias_method_chain :save, :bullet def save_with_bullet!(*args, &proc) was_new_record = new_record? save_without_bullet!(*args, &proc).tap do |result| Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record end end alias_method_chain :save!, :bullet end ::ActiveRecord::Associations::Preloader.class_eval do # include query for one to many associations. # keep this eager loadings. alias_method :origin_initialize, :initialize def initialize(records, associations, preload_scope = nil) origin_initialize(records, associations, preload_scope) if Bullet.start? records = [records].flatten.compact.uniq return if records.empty? records.each do |record| Bullet::Detector::Association.add_object_associations(record, associations) end Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations) end end end ::ActiveRecord::FinderMethods.class_eval do # add includes in scope alias_method :origin_find_with_associations, :find_with_associations def find_with_associations records = origin_find_with_associations if Bullet.start? associations = (eager_load_values + includes_values).uniq records.each do |record| Bullet::Detector::Association.add_object_associations(record, associations) end Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations) end records end end ::ActiveRecord::Associations::JoinDependency.class_eval do alias_method :origin_instantiate, :instantiate alias_method :origin_construct_association, :construct_association def instantiate(rows) @bullet_eager_loadings = {} records = origin_instantiate(rows) if Bullet.start? @bullet_eager_loadings.each do |_klazz, eager_loadings_hash| objects = eager_loadings_hash.keys Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a) end end records end # call join associations def construct_association(record, join, row) result = origin_construct_association(record, join, row) if Bullet.start? associations = join.reflection.name Bullet::Detector::Association.add_object_associations(record, associations) Bullet::Detector::NPlusOneQuery.call_association(record, associations) @bullet_eager_loadings[record.class] ||= {} @bullet_eager_loadings[record.class][record] ||= Set.new @bullet_eager_loadings[record.class][record] << associations end result end end ::ActiveRecord::Associations::CollectionAssociation.class_eval do # call one to many associations alias_method :origin_load_target, :load_target def load_target if Bullet.start? Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) end origin_load_target end alias_method :origin_include?, :include? def include?(object) if Bullet.start? Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) end origin_include?(object) end end ::ActiveRecord::Associations::HasManyAssociation.class_eval do alias_method :origin_empty?, :empty? def empty? if Bullet.start? && !loaded? && !has_cached_counter?(@reflection) Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) end origin_empty? end end ::ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do alias_method :origin_empty?, :empty? def empty? if Bullet.start? && !loaded? Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) end origin_empty? end end ::ActiveRecord::Associations::SingularAssociation.class_eval do # call has_one and belongs_to associations alias_method :origin_reader, :reader def reader(force_reload = false) result = origin_reader(force_reload) if Bullet.start? unless @inversed Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) Bullet::Detector::NPlusOneQuery.add_possible_objects(result) end end result end end ::ActiveRecord::Associations::HasManyAssociation.class_eval do alias_method :origin_has_cached_counter?, :has_cached_counter? # rubocop:disable Style/MethodCallWithoutArgsParentheses def has_cached_counter?(reflection = reflection()) result = origin_has_cached_counter?(reflection) if Bullet.start? && !result Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) end result end # rubocop:enable Style/MethodCallWithoutArgsParentheses end end
find(*args)
click to toggle source
# File lib/bullet/active_record42.rb, line 10 def find(*args) result = origin_find(*args) if Bullet.start? if result.is_a? Array Bullet::Detector::NPlusOneQuery.add_possible_objects(result) Bullet::Detector::CounterCache.add_possible_objects(result) elsif result.is_a? ::ActiveRecord::Base Bullet::Detector::NPlusOneQuery.add_impossible_object(result) Bullet::Detector::CounterCache.add_impossible_object(result) end end result end
Also aliased as: origin_find
find_by_sql(sql, binds = [])
click to toggle source
# File lib/bullet/active_record4.rb, line 10 def find_by_sql(sql, binds = []) result = origin_find_by_sql(sql, binds) if Bullet.start? if result.is_a? Array if result.size > 1 Bullet::Detector::NPlusOneQuery.add_possible_objects(result) Bullet::Detector::CounterCache.add_possible_objects(result) elsif result.size == 1 Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first) Bullet::Detector::CounterCache.add_impossible_object(result.first) end elsif result.is_a? ::ActiveRecord::Base Bullet::Detector::NPlusOneQuery.add_impossible_object(result) Bullet::Detector::CounterCache.add_impossible_object(result) end end result end
Also aliased as: origin_find_by_sql, origin_find_by_sql, origin_find_by_sql
new(records, associations, preload_scope = nil)
click to toggle source
# File lib/bullet/active_record4.rb, line 72 def initialize(records, associations, preload_scope = nil) origin_initialize(records, associations, preload_scope) if Bullet.start? records = [records].flatten.compact.uniq return if records.empty? records.each do |record| Bullet::Detector::Association.add_object_associations(record, associations) end Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations) end end
Public Instance Methods
construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
click to toggle source
# File lib/bullet/active_record42.rb, line 137 def construct(ar_parent, parent, row, rs, seen, model_cache, aliases) if Bullet.start? unless ar_parent.nil? parent.children.each do |node| key = aliases.column_alias(node, node.primary_key) id = row[key] next unless id.nil? associations = node.reflection.name Bullet::Detector::Association.add_object_associations(ar_parent, associations) Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations) @bullet_eager_loadings[ar_parent.class] ||= {} @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new @bullet_eager_loadings[ar_parent.class][ar_parent] << associations end end end origin_construct(ar_parent, parent, row, rs, seen, model_cache, aliases) end
construct_association(record, join, row)
click to toggle source
call join associations
# File lib/bullet/active_record4.rb, line 119 def construct_association(record, join, row) result = origin_construct_association(record, join, row) if Bullet.start? associations = join.reflection.name Bullet::Detector::Association.add_object_associations(record, associations) Bullet::Detector::NPlusOneQuery.call_association(record, associations) @bullet_eager_loadings[record.class] ||= {} @bullet_eager_loadings[record.class][record] ||= Set.new @bullet_eager_loadings[record.class][record] << associations end result end
construct_model(record, node, row, model_cache, id, aliases)
click to toggle source
call join associations
# File lib/bullet/active_record41.rb, line 122 def construct_model(record, node, row, model_cache, id, aliases) result = origin_construct_model(record, node, row, model_cache, id, aliases) if Bullet.start? associations = node.reflection.name Bullet::Detector::Association.add_object_associations(record, associations) Bullet::Detector::NPlusOneQuery.call_association(record, associations) @bullet_eager_loadings[record.class] ||= {} @bullet_eager_loadings[record.class][record] ||= Set.new @bullet_eager_loadings[record.class][record] << associations end result end
count_records()
click to toggle source
# File lib/bullet/active_record41.rb, line 182 def count_records result = has_cached_counter? if Bullet.start? && !result Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) end origin_count_records end
empty?()
click to toggle source
# File lib/bullet/active_record4.rb, line 156 def empty? if Bullet.start? && !loaded? && !has_cached_counter?(@reflection) Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) end origin_empty? end
find_with_associations()
click to toggle source
# File lib/bullet/active_record4.rb, line 88 def find_with_associations records = origin_find_with_associations if Bullet.start? associations = (eager_load_values + includes_values).uniq records.each do |record| Bullet::Detector::Association.add_object_associations(record, associations) end Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations) end records end
has_cached_counter?(reflection = reflection())
click to toggle source
rubocop:disable Style/MethodCallWithoutArgsParentheses
# File lib/bullet/active_record4.rb, line 193 def has_cached_counter?(reflection = reflection()) result = origin_has_cached_counter?(reflection) if Bullet.start? && !result Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) end result end
include?(object)
click to toggle source
# File lib/bullet/active_record4.rb, line 146 def include?(object) if Bullet.start? Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) end origin_include?(object) end
instantiate(rows)
click to toggle source
# File lib/bullet/active_record4.rb, line 105 def instantiate(rows) @bullet_eager_loadings = {} records = origin_instantiate(rows) if Bullet.start? @bullet_eager_loadings.each do |_klazz, eager_loadings_hash| objects = eager_loadings_hash.keys Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a) end end records end
load_target()
click to toggle source
# File lib/bullet/active_record4.rb, line 138 def load_target if Bullet.start? Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) end origin_load_target end
preloaders_for_one(association, records, scope)
click to toggle source
Calls superclass method
# File lib/bullet/active_record5.rb, line 67 def preloaders_for_one(association, records, scope) if Bullet.start? records.compact! if records.first.class.name !~ /^HABTM_/ records.each do |record| Bullet::Detector::Association.add_object_associations(record, association) end Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association) end end super end
preloaders_on(association, records, scope)
click to toggle source
# File lib/bullet/active_record41.rb, line 73 def preloaders_on(association, records, scope) if Bullet.start? records.compact! if records.first.class.name !~ /^HABTM_/ records.each do |record| Bullet::Detector::Association.add_object_associations(record, association) end Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association) end end origin_preloaders_on(association, records, scope) end
reader(force_reload = false)
click to toggle source
# File lib/bullet/active_record4.rb, line 177 def reader(force_reload = false) result = origin_reader(force_reload) if Bullet.start? unless @inversed Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) Bullet::Detector::NPlusOneQuery.add_possible_objects(result) end end result end
records()
click to toggle source
if select a collection of objects, then these objects have possible to cause N+1 query. if select only one object, then the only one object has impossible to cause N+1 query.
Calls superclass method
# File lib/bullet/active_record5.rb, line 49 def records result = super if Bullet.start? if result.first.class.name !~ /^HABTM_/ if result.size > 1 Bullet::Detector::NPlusOneQuery.add_possible_objects(result) Bullet::Detector::CounterCache.add_possible_objects(result) elsif result.size == 1 Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first) Bullet::Detector::CounterCache.add_impossible_object(result.first) end end end result end
save_with_bullet(*args, &proc)
click to toggle source
# File lib/bullet/active_record4.rb, line 51 def save_with_bullet(*args, &proc) was_new_record = new_record? save_without_bullet(*args, &proc).tap do |result| Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record end end
save_with_bullet!(*args, &proc)
click to toggle source
# File lib/bullet/active_record4.rb, line 59 def save_with_bullet!(*args, &proc) was_new_record = new_record? save_without_bullet!(*args, &proc).tap do |result| Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record end end
target()
click to toggle source
call has_one and belongs_to associations
Calls superclass method
# File lib/bullet/active_record5.rb, line 208 def target result = super() if Bullet.start? if owner.class.name !~ /^HABTM_/ && !@inversed Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet::Detector::NPlusOneQuery.impossible?(owner) Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result else Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result end end end result end
to_a()
click to toggle source
if select a collection of objects, then these objects have possible to cause N+1 query. if select only one object, then the only one object has impossible to cause N+1 query.
# File lib/bullet/active_record4.rb, line 35 def to_a records = origin_to_a if Bullet.start? if records.size > 1 Bullet::Detector::NPlusOneQuery.add_possible_objects(records) Bullet::Detector::CounterCache.add_possible_objects(records) elsif records.size == 1 Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first) Bullet::Detector::CounterCache.add_impossible_object(records.first) end end records end