bullet 4.4.0 → 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.
@@ -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|
@@ -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
@@ -30,7 +30,7 @@ module Bullet
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
 
@@ -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
@@ -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
@@ -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
@@ -30,7 +30,7 @@ module Bullet
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
 
@@ -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
@@ -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
@@ -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
@@ -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.