bullet 4.3.1 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,11 +12,11 @@ module Bullet
12
12
 
13
13
  if records
14
14
  if records.size > 1
15
- Bullet::Detector::Association.add_possible_objects(records)
16
- Bullet::Detector::Counter.add_possible_objects(records)
15
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
16
+ Bullet::Detector::CounterCache.add_possible_objects(records)
17
17
  elsif records.size == 1
18
- Bullet::Detector::Association.add_impossible_object(records.first)
19
- Bullet::Detector::Counter.add_impossible_object(records.first)
18
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
19
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
20
20
  end
21
21
  end
22
22
 
@@ -35,7 +35,7 @@ module Bullet
35
35
  records.each do |record|
36
36
  Bullet::Detector::Association.add_object_associations(record, associations)
37
37
  end
38
- Bullet::Detector::Association.add_eager_loadings(records, associations)
38
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
39
39
  origin_preload_associations(records, associations, preload_options={})
40
40
  end
41
41
  end
@@ -50,7 +50,7 @@ module Bullet
50
50
  Bullet::Detector::Association.add_object_associations(record, associations)
51
51
  Bullet::Detector::NPlusOneQuery.call_association(record, associations)
52
52
  end
53
- Bullet::Detector::Association.add_eager_loadings(records, associations)
53
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
54
54
  records
55
55
  end
56
56
  end
@@ -94,7 +94,7 @@ module Bullet
94
94
  # avoid stack level too deep
95
95
  result = origin_load_target
96
96
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.any? {|c| c.include?("load_target") }
97
- Bullet::Detector::Association.add_possible_objects(result)
97
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
98
98
  result
99
99
  end
100
100
  end
@@ -103,7 +103,7 @@ module Bullet
103
103
  alias_method :origin_has_cached_counter?, :has_cached_counter?
104
104
  def has_cached_counter?
105
105
  result = origin_has_cached_counter?
106
- Bullet::Detector::Counter.add_counter_cache(@owner, @reflection.name) unless result
106
+ Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) unless result
107
107
  result
108
108
  end
109
109
  end
@@ -112,7 +112,7 @@ module Bullet
112
112
  alias_method :origin_has_cached_counter?, :has_cached_counter?
113
113
  def has_cached_counter?
114
114
  result = origin_has_cached_counter?
115
- Bullet::Detector::Counter.add_counter_cache(@owner, @reflection.name) unless result
115
+ Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) unless result
116
116
  result
117
117
  end
118
118
  end
@@ -9,11 +9,11 @@ module Bullet
9
9
  def to_a
10
10
  records = origin_to_a
11
11
  if records.size > 1
12
- Bullet::Detector::Association.add_possible_objects(records)
13
- Bullet::Detector::Counter.add_possible_objects(records)
12
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
13
+ Bullet::Detector::CounterCache.add_possible_objects(records)
14
14
  elsif records.size == 1
15
- Bullet::Detector::Association.add_impossible_object(records.first)
16
- Bullet::Detector::Counter.add_impossible_object(records.first)
15
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
16
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
17
17
  end
18
18
  records
19
19
  end
@@ -29,7 +29,7 @@ module Bullet
29
29
  records.each do |record|
30
30
  Bullet::Detector::Association.add_object_associations(record, associations)
31
31
  end
32
- Bullet::Detector::Association.add_eager_loadings(records, associations)
32
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
33
33
  origin_preload_associations(records, associations, preload_options={})
34
34
  end
35
35
  end
@@ -44,7 +44,7 @@ module Bullet
44
44
  Bullet::Detector::Association.add_object_associations(record, associations)
45
45
  Bullet::Detector::NPlusOneQuery.call_association(record, associations)
46
46
  end
47
- Bullet::Detector::Association.add_eager_loadings(records, associations)
47
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
48
48
  records
49
49
  end
50
50
  end
@@ -88,7 +88,7 @@ module Bullet
88
88
  # avoid stack level too deep
89
89
  result = origin_load_target
90
90
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.any? { |c| c.include?("load_target") }
91
- Bullet::Detector::Association.add_possible_objects(result)
91
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
92
92
  result
93
93
  end
94
94
  end
@@ -98,7 +98,7 @@ module Bullet
98
98
 
99
99
  def has_cached_counter?
100
100
  result = origin_has_cached_counter?
101
- Bullet::Detector::Counter.add_counter_cache(@owner, @reflection.name) unless result
101
+ Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) unless result
102
102
  result
103
103
  end
104
104
  end
@@ -107,7 +107,7 @@ module Bullet
107
107
  alias_method :origin_has_cached_counter?, :has_cached_counter?
108
108
  def has_cached_counter?
109
109
  result = origin_has_cached_counter?
110
- Bullet::Detector::Counter.add_counter_cache(@owner, @reflection.name) unless result
110
+ Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) unless result
111
111
  result
112
112
  end
113
113
  end
@@ -9,11 +9,11 @@ module Bullet
9
9
  def to_a
10
10
  records = origin_to_a
11
11
  if records.size > 1
12
- Bullet::Detector::Association.add_possible_objects(records)
13
- Bullet::Detector::Counter.add_possible_objects(records)
12
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
13
+ Bullet::Detector::CounterCache.add_possible_objects(records)
14
14
  elsif records.size == 1
15
- Bullet::Detector::Association.add_impossible_object(records.first)
16
- Bullet::Detector::Counter.add_impossible_object(records.first)
15
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
16
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
17
17
  end
18
18
  records
19
19
  end
@@ -23,14 +23,14 @@ module Bullet
23
23
  # include query for one to many associations.
24
24
  # keep this eager loadings.
25
25
  alias_method :origin_initialize, :initialize
26
- def initialize(records, associations, preload_options = {})
27
- origin_initialize(records, associations, preload_options)
26
+ def initialize(records, associations, preload_scope = nil)
27
+ origin_initialize(records, associations, preload_scope)
28
28
  records = [records].flatten.compact.uniq
29
29
  return if records.empty?
30
30
  records.each do |record|
31
31
  Bullet::Detector::Association.add_object_associations(record, associations)
32
32
  end
33
- Bullet::Detector::Association.add_eager_loadings(records, associations)
33
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
34
34
  end
35
35
  end
36
36
 
@@ -39,12 +39,12 @@ module Bullet
39
39
  alias_method :origin_find_with_associations, :find_with_associations
40
40
  def find_with_associations
41
41
  records = origin_find_with_associations
42
- associations = (@eager_load_values + @includes_values).uniq
42
+ associations = (eager_load_values + includes_values).uniq
43
43
  records.each do |record|
44
44
  Bullet::Detector::Association.add_object_associations(record, associations)
45
45
  Bullet::Detector::NPlusOneQuery.call_association(record, associations)
46
46
  end
47
- Bullet::Detector::Association.add_eager_loadings(records, associations)
47
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
48
48
  records
49
49
  end
50
50
  end
@@ -75,7 +75,7 @@ module Bullet
75
75
  def reader(force_reload = false)
76
76
  result = origin_reader(force_reload)
77
77
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
78
- Bullet::Detector::Association.add_possible_objects(result)
78
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
79
79
  result
80
80
  end
81
81
  end
@@ -85,7 +85,7 @@ module Bullet
85
85
 
86
86
  def has_cached_counter?(reflection = reflection)
87
87
  result = origin_has_cached_counter?(reflection)
88
- Bullet::Detector::Counter.add_counter_cache(owner, reflection.name) unless result
88
+ Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) unless result
89
89
  result
90
90
  end
91
91
  end
@@ -0,0 +1,94 @@
1
+ module Bullet
2
+ module ActiveRecord
3
+ def self.enable
4
+ require 'active_record'
5
+ ::ActiveRecord::Relation.class_eval do
6
+ alias_method :origin_to_a, :to_a
7
+ # if select a collection of objects, then these objects have possible to cause N+1 query.
8
+ # if select only one object, then the only one object has impossible to cause N+1 query.
9
+ def to_a
10
+ records = origin_to_a
11
+ if records.size > 1
12
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
13
+ Bullet::Detector::CounterCache.add_possible_objects(records)
14
+ elsif records.size == 1
15
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
16
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
17
+ end
18
+ records
19
+ end
20
+ end
21
+
22
+ ::ActiveRecord::Associations::Preloader.class_eval do
23
+ # include query for one to many associations.
24
+ # keep this eager loadings.
25
+ alias_method :origin_initialize, :initialize
26
+ def initialize(records, associations, preload_scope = nil)
27
+ origin_initialize(records, associations, preload_scope)
28
+ records = [records].flatten.compact.uniq
29
+ return if records.empty?
30
+ records.each do |record|
31
+ Bullet::Detector::Association.add_object_associations(record, associations)
32
+ end
33
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
34
+ end
35
+ end
36
+
37
+ ::ActiveRecord::FinderMethods.class_eval do
38
+ # add includes in scope
39
+ alias_method :origin_find_with_associations, :find_with_associations
40
+ def find_with_associations
41
+ records = origin_find_with_associations
42
+ associations = (eager_load_values + includes_values).uniq
43
+ records.each do |record|
44
+ Bullet::Detector::Association.add_object_associations(record, associations)
45
+ Bullet::Detector::NPlusOneQuery.call_association(record, associations)
46
+ end
47
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
48
+ records
49
+ end
50
+ end
51
+
52
+ ::ActiveRecord::Associations::JoinDependency.class_eval do
53
+ alias_method :origin_construct_association, :construct_association
54
+ # call join associations
55
+ def construct_association(record, join, row)
56
+ associations = join.reflection.name
57
+ Bullet::Detector::Association.add_object_associations(record, associations)
58
+ Bullet::Detector::NPlusOneQuery.call_association(record, associations)
59
+ origin_construct_association(record, join, row)
60
+ end
61
+ end
62
+
63
+ ::ActiveRecord::Associations::CollectionAssociation.class_eval do
64
+ # call one to many associations
65
+ alias_method :origin_load_target, :load_target
66
+ def load_target
67
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
68
+ origin_load_target
69
+ end
70
+ end
71
+
72
+ ::ActiveRecord::Associations::SingularAssociation.class_eval do
73
+ # call has_one and belongs_to associations
74
+ alias_method :origin_reader, :reader
75
+ def reader(force_reload = false)
76
+ result = origin_reader(force_reload)
77
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
78
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
79
+ result
80
+ end
81
+ end
82
+
83
+ ::ActiveRecord::Associations::HasManyAssociation.class_eval do
84
+ alias_method :origin_has_cached_counter?, :has_cached_counter?
85
+
86
+ def has_cached_counter?(reflection = reflection)
87
+ result = origin_has_cached_counter?(reflection)
88
+ Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) unless result
89
+ result
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -24,8 +24,10 @@ module Bullet
24
24
  'active_record2'
25
25
  elsif active_record30?
26
26
  'active_record3'
27
- elsif active_record31? || active_record32? || active_record4?
27
+ elsif active_record31? || active_record32?
28
28
  'active_record3x'
29
+ elsif active_record4?
30
+ 'active_record4'
29
31
  end
30
32
  end
31
33
  end
@@ -20,56 +20,15 @@ module Bullet
20
20
  end
21
21
 
22
22
  def add_object_associations(object, associations)
23
+ return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
23
24
  object_associations.add(object.bullet_ar_key, associations) if object.id
24
25
  end
25
26
 
26
27
  def add_call_object_associations(object, associations)
28
+ return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
27
29
  call_object_associations.add(object.bullet_ar_key, associations) if object.id
28
30
  end
29
31
 
30
- def add_possible_objects(object_or_objects)
31
- return unless object_or_objects
32
- if object_or_objects.is_a? Array
33
- object_or_objects.each { |object| possible_objects.add object.bullet_ar_key }
34
- else
35
- possible_objects.add object_or_objects.bullet_ar_key if object_or_objects.id
36
- end
37
- end
38
-
39
- def add_impossible_object(object)
40
- impossible_objects.add object.bullet_ar_key if object.id
41
- end
42
-
43
- def add_eager_loadings(objects, associations)
44
- bullet_ar_keys = objects.map(&:bullet_ar_key)
45
-
46
- to_add = nil
47
- to_merge, to_delete = [], []
48
- eager_loadings.each do |k, v|
49
- key_objects_overlap = k & bullet_ar_keys
50
-
51
- next if key_objects_overlap.empty?
52
-
53
- if key_objects_overlap == k
54
- to_add = [k, associations]
55
- break
56
- else
57
- to_merge << [key_objects_overlap, ( eager_loadings[k].dup << associations )]
58
-
59
- keys_without_objects = k - bullet_ar_keys
60
- to_merge << [keys_without_objects, eager_loadings[k]]
61
- to_delete << k
62
- bullet_ar_keys = bullet_ar_keys - k
63
- end
64
- end
65
-
66
- eager_loadings.add *to_add if to_add
67
- to_merge.each { |k,val| eager_loadings.merge k, val }
68
- to_delete.each { |k| eager_loadings.delete k }
69
-
70
- eager_loadings.add bullet_ar_keys, associations unless bullet_ar_keys.empty?
71
- end
72
-
73
32
  private
74
33
  # object_associations keep the object relationships
75
34
  # that the object has many associations.
@@ -1,6 +1,6 @@
1
1
  module Bullet
2
2
  module Detector
3
- class Counter < Base
3
+ class CounterCache < Base
4
4
  class <<self
5
5
  def clear
6
6
  @@possible_objects = nil
@@ -8,12 +8,16 @@ module Bullet
8
8
  end
9
9
 
10
10
  def add_counter_cache(object, associations)
11
+ return unless Bullet.counter_cache_enable?
12
+
11
13
  if conditions_met?(object.bullet_ar_key, associations)
12
14
  create_notification object.class.to_s, associations
13
15
  end
14
16
  end
15
17
 
16
18
  def add_possible_objects(object_or_objects)
19
+ return unless Bullet.counter_cache_enable?
20
+
17
21
  if object_or_objects.is_a? Array
18
22
  object_or_objects.each { |object| possible_objects.add object.bullet_ar_key }
19
23
  else
@@ -22,13 +26,19 @@ module Bullet
22
26
  end
23
27
 
24
28
  def add_impossible_object(object)
29
+ return unless Bullet.counter_cache_enable?
30
+
25
31
  impossible_objects.add object.bullet_ar_key
26
32
  end
27
33
 
28
34
  private
29
35
  def create_notification(klazz, associations)
30
- notice = Bullet::Notification::CounterCache.new klazz, associations
31
- Bullet.notification_collector.add notice
36
+ notify_associations = Array(associations) - Bullet.get_whitelist_associations(:counter_cache, klazz)
37
+
38
+ if notify_associations.present?
39
+ notice = Bullet::Notification::CounterCache.new klazz, notify_associations
40
+ Bullet.notification_collector.add notice
41
+ end
32
42
  end
33
43
 
34
44
  def possible_objects
@@ -15,10 +15,29 @@ module Bullet
15
15
  end
16
16
  end
17
17
 
18
+ def add_possible_objects(object_or_objects)
19
+ return unless Bullet.n_plus_one_query_enable?
20
+ return if object_or_objects.blank?
21
+ if object_or_objects.is_a? Array
22
+ object_or_objects.each { |object| possible_objects.add object.bullet_ar_key }
23
+ else
24
+ possible_objects.add object_or_objects.bullet_ar_key if object_or_objects.id
25
+ end
26
+ end
27
+
28
+ def add_impossible_object(object)
29
+ return unless Bullet.n_plus_one_query_enable?
30
+ impossible_objects.add object.bullet_ar_key if object.id
31
+ end
32
+
18
33
  private
19
34
  def create_notification(callers, klazz, associations)
20
- notice = Bullet::Notification::NPlusOneQuery.new(callers, klazz, associations)
21
- Bullet.notification_collector.add(notice)
35
+ notify_associations = Array(associations) - Bullet.get_whitelist_associations(:n_plus_one_query, klazz)
36
+
37
+ if notify_associations.present?
38
+ notice = Bullet::Notification::NPlusOneQuery.new(callers, klazz, notify_associations)
39
+ Bullet.notification_collector.add(notice)
40
+ end
22
41
  end
23
42
 
24
43
  # decide whether the object.associations is unpreloaded or not.
@@ -1,12 +1,14 @@
1
1
  module Bullet
2
2
  module Detector
3
- class UnusedEagerAssociation < Association
3
+ class UnusedEagerLoading < Association
4
4
  class <<self
5
5
  # check if there are unused preload associations.
6
6
  # get related_objects from eager_loadings associated with object and associations
7
7
  # get call_object_association from associations of call_object_associations whose object is in related_objects
8
8
  # if association not in call_object_association, then the object => association - call_object_association is ununsed preload assocations
9
9
  def check_unused_preload_associations
10
+ return unless Bullet.unused_eager_loading_enable?
11
+
10
12
  @@checked = true
11
13
  object_associations.each do |bullet_ar_key, associations|
12
14
  object_association_diff = diff_object_associations bullet_ar_key, associations
@@ -16,10 +18,45 @@ module Bullet
16
18
  end
17
19
  end
18
20
 
21
+ def add_eager_loadings(objects, associations)
22
+ return unless Bullet.unused_eager_loading_enable?
23
+ bullet_ar_keys = objects.map(&:bullet_ar_key)
24
+
25
+ to_add = nil
26
+ to_merge, to_delete = [], []
27
+ eager_loadings.each do |k, v|
28
+ key_objects_overlap = k & bullet_ar_keys
29
+
30
+ next if key_objects_overlap.empty?
31
+
32
+ if key_objects_overlap == k
33
+ to_add = [k, associations]
34
+ break
35
+ else
36
+ to_merge << [key_objects_overlap, ( eager_loadings[k].dup << associations )]
37
+
38
+ keys_without_objects = k - bullet_ar_keys
39
+ to_merge << [keys_without_objects, eager_loadings[k]]
40
+ to_delete << k
41
+ bullet_ar_keys = bullet_ar_keys - k
42
+ end
43
+ end
44
+
45
+ eager_loadings.add *to_add if to_add
46
+ to_merge.each { |k,val| eager_loadings.merge k, val }
47
+ to_delete.each { |k| eager_loadings.delete k }
48
+
49
+ eager_loadings.add bullet_ar_keys, associations unless bullet_ar_keys.empty?
50
+ end
51
+
19
52
  private
20
53
  def create_notification(klazz, associations)
21
- notice = Bullet::Notification::UnusedEagerLoading.new(klazz, associations)
22
- Bullet.notification_collector.add(notice)
54
+ notify_associations = Array(associations) - Bullet.get_whitelist_associations(:unused_eager_loading, klazz)
55
+
56
+ if notify_associations.present?
57
+ notice = Bullet::Notification::UnusedEagerLoading.new(klazz, notify_associations)
58
+ Bullet.notification_collector.add(notice)
59
+ end
23
60
  end
24
61
 
25
62
  def call_associations(bullet_ar_key, associations)
@@ -3,7 +3,7 @@ module Bullet
3
3
  autoload :Base, 'bullet/detector/base'
4
4
  autoload :Association, 'bullet/detector/association'
5
5
  autoload :NPlusOneQuery, 'bullet/detector/n_plus_one_query'
6
- autoload :UnusedEagerAssociation, 'bullet/detector/unused_eager_association'
7
- autoload :Counter, 'bullet/detector/counter'
6
+ autoload :UnusedEagerLoading, 'bullet/detector/unused_eager_loading'
7
+ autoload :CounterCache, 'bullet/detector/counter_cache'
8
8
  end
9
9
  end
@@ -11,22 +11,22 @@ module Bullet
11
11
 
12
12
  def first
13
13
  result = origin_first
14
- Bullet::Detector::Association.add_impossible_object(result) if result
14
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
15
15
  result
16
16
  end
17
17
 
18
18
  def last
19
19
  result = origin_last
20
- Bullet::Detector::Association.add_impossible_object(result) if result
20
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
21
21
  result
22
22
  end
23
23
 
24
24
  def iterate(&block)
25
25
  records = execute.to_a
26
26
  if records.size > 1
27
- Bullet::Detector::Association.add_possible_objects(records)
27
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
28
28
  elsif records.size == 1
29
- Bullet::Detector::Association.add_impossible_object(records.first)
29
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
30
30
  end
31
31
  origin_iterate(&block)
32
32
  end
@@ -36,7 +36,7 @@ module Bullet
36
36
  docs.each do |doc|
37
37
  Bullet::Detector::Association.add_object_associations(doc, associations)
38
38
  end
39
- Bullet::Detector::Association.add_eager_loadings(docs, associations)
39
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(docs, associations)
40
40
  origin_eager_load(docs)
41
41
  end
42
42
  end
@@ -10,22 +10,22 @@ module Bullet
10
10
 
11
11
  def first
12
12
  result = origin_first
13
- Bullet::Detector::Association.add_impossible_object(result) if result
13
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
14
14
  result
15
15
  end
16
16
 
17
17
  def last
18
18
  result = origin_last
19
- Bullet::Detector::Association.add_impossible_object(result) if result
19
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
20
20
  result
21
21
  end
22
22
 
23
23
  def each(&block)
24
24
  records = query.map{ |doc| ::Mongoid::Factory.from_db(klass, doc) }
25
25
  if records.length > 1
26
- Bullet::Detector::Association.add_possible_objects(records)
26
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
27
27
  elsif records.size == 1
28
- Bullet::Detector::Association.add_impossible_object(records.first)
28
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
29
29
  end
30
30
  origin_each(&block)
31
31
  end
@@ -33,9 +33,9 @@ module Bullet
33
33
  def eager_load(docs)
34
34
  associations = criteria.inclusions.map(&:name)
35
35
  docs.each do |doc|
36
- Bullet::Detector::Association.add_object_associations(doc, associations)
36
+ Bullet::Detector::NPlusOneQuery.add_object_associations(doc, associations)
37
37
  end
38
- Bullet::Detector::Association.add_eager_loadings(docs, associations)
38
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(docs, associations)
39
39
  origin_eager_load(docs)
40
40
  end
41
41
  end
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Bullet
3
- VERSION = "4.3.1"
3
+ VERSION = "4.5.0"
4
4
  end
data/lib/bullet.rb CHANGED
@@ -30,18 +30,19 @@ module Bullet
30
30
  end
31
31
 
32
32
  class <<self
33
- attr_accessor :enable
34
- attr_reader :notification_collector
33
+ attr_writer :enable, :n_plus_one_query_enable, :unused_eager_loading_enable, :counter_cache_enable
34
+ attr_reader :notification_collector, :whitelist
35
35
 
36
36
  delegate :alert=, :console=, :growl=, :rails_logger=, :xmpp=, :airbrake=, :to => UniformNotifier
37
37
 
38
38
  DETECTORS = [ Bullet::Detector::NPlusOneQuery,
39
- Bullet::Detector::UnusedEagerAssociation,
40
- Bullet::Detector::Counter ]
39
+ Bullet::Detector::UnusedEagerLoading,
40
+ Bullet::Detector::CounterCache ]
41
41
 
42
42
  def enable=(enable)
43
- @enable = enable
43
+ @enable = @n_plus_one_query_enable = @unused_eager_loading_enable = @counter_cache_enable = enable
44
44
  if enable?
45
+ reset_whitelist
45
46
  if mongoid?
46
47
  Bullet::Mongoid.enable
47
48
  end
@@ -53,7 +54,32 @@ module Bullet
53
54
  end
54
55
 
55
56
  def enable?
56
- @enable == true
57
+ !!@enable
58
+ end
59
+
60
+ def n_plus_one_query_enable?
61
+ self.enable? && !!@n_plus_one_query_enable
62
+ end
63
+
64
+ def unused_eager_loading_enable?
65
+ self.enable? && !!@unused_eager_loading_enable
66
+ end
67
+
68
+ def counter_cache_enable?
69
+ self.enable? && !!@counter_cache_enable
70
+ end
71
+
72
+ def add_whitelist(options)
73
+ @whitelist[options[:type]][options[:class_name].classify] ||= []
74
+ @whitelist[options[:type]][options[:class_name].classify] << options[:association].to_s.tableize.to_sym
75
+ end
76
+
77
+ def get_whitelist_associations(type, class_name)
78
+ Array(@whitelist[type][class_name])
79
+ end
80
+
81
+ def reset_whitelist
82
+ @whitelist = {:n_plus_one_query => {}, :unused_eager_loading => {}, :counter_cache => {}}
57
83
  end
58
84
 
59
85
  def bullet_logger=(active)
@@ -82,7 +108,7 @@ module Bullet
82
108
  end
83
109
 
84
110
  def notification?
85
- Bullet::Detector::UnusedEagerAssociation.check_unused_preload_associations
111
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
86
112
  notification_collector.notifications_present?
87
113
  end
88
114
 
@@ -101,6 +127,15 @@ module Bullet
101
127
  end
102
128
  end
103
129
 
130
+ def warnings
131
+ notification_collector.collection.inject({}) do |warnings, notification|
132
+ warning_type = notification.class.to_s.split(':').last.tableize
133
+ warnings[warning_type] ||= []
134
+ warnings[warning_type] << notification
135
+ warnings
136
+ end
137
+ end
138
+
104
139
  private
105
140
  def for_each_active_notifier_with_notification
106
141
  UniformNotifier.active_notifiers.each do |notifier|