bullet 8.0.8 → 8.2.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.
@@ -13,22 +13,8 @@ module Bullet
13
13
  def active_record_version
14
14
  @active_record_version ||=
15
15
  begin
16
- if active_record40?
17
- 'active_record4'
18
- elsif active_record41?
19
- 'active_record41'
20
- elsif active_record42?
21
- 'active_record42'
22
- elsif active_record50?
23
- 'active_record5'
24
- elsif active_record51?
25
- 'active_record5'
26
- elsif active_record52?
27
- 'active_record52'
28
- elsif active_record60?
29
- 'active_record60'
30
- elsif active_record61?
31
- 'active_record61'
16
+ if active_record6_or_older?
17
+ raise "Bullet no longer supports active_record #{::ActiveRecord::VERSION::STRING}"
32
18
  elsif active_record70?
33
19
  'active_record70'
34
20
  elsif active_record71?
@@ -37,6 +23,8 @@ module Bullet
37
23
  'active_record72'
38
24
  elsif active_record80?
39
25
  'active_record80'
26
+ elsif active_record81?
27
+ 'active_record81'
40
28
  else
41
29
  raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
42
30
  end
@@ -64,16 +52,8 @@ module Bullet
64
52
  end
65
53
  end
66
54
 
67
- def active_record4?
68
- active_record? && ::ActiveRecord::VERSION::MAJOR == 4
69
- end
70
-
71
- def active_record5?
72
- active_record? && ::ActiveRecord::VERSION::MAJOR == 5
73
- end
74
-
75
- def active_record6?
76
- active_record? && ::ActiveRecord::VERSION::MAJOR == 6
55
+ def active_record6_or_older?
56
+ active_record? && ::ActiveRecord::VERSION::MAJOR < 7
77
57
  end
78
58
 
79
59
  def active_record7?
@@ -84,38 +64,6 @@ module Bullet
84
64
  active_record? && ::ActiveRecord::VERSION::MAJOR == 8
85
65
  end
86
66
 
87
- def active_record40?
88
- active_record4? && ::ActiveRecord::VERSION::MINOR == 0
89
- end
90
-
91
- def active_record41?
92
- active_record4? && ::ActiveRecord::VERSION::MINOR == 1
93
- end
94
-
95
- def active_record42?
96
- active_record4? && ::ActiveRecord::VERSION::MINOR == 2
97
- end
98
-
99
- def active_record50?
100
- active_record5? && ::ActiveRecord::VERSION::MINOR == 0
101
- end
102
-
103
- def active_record51?
104
- active_record5? && ::ActiveRecord::VERSION::MINOR == 1
105
- end
106
-
107
- def active_record52?
108
- active_record5? && ::ActiveRecord::VERSION::MINOR == 2
109
- end
110
-
111
- def active_record60?
112
- active_record6? && ::ActiveRecord::VERSION::MINOR == 0
113
- end
114
-
115
- def active_record61?
116
- active_record6? && ::ActiveRecord::VERSION::MINOR == 1
117
- end
118
-
119
67
  def active_record70?
120
68
  active_record7? && ::ActiveRecord::VERSION::MINOR == 0
121
69
  end
@@ -132,6 +80,10 @@ module Bullet
132
80
  active_record8? && ::ActiveRecord::VERSION::MINOR == 0
133
81
  end
134
82
 
83
+ def active_record81?
84
+ active_record8? && ::ActiveRecord::VERSION::MINOR == 1
85
+ end
86
+
135
87
  def mongoid4x?
136
88
  mongoid? && ::Mongoid::VERSION =~ /\A4/
137
89
  end
@@ -8,7 +8,7 @@ module Bullet
8
8
  class << self
9
9
  def add_object_associations(object, associations)
10
10
  return unless Bullet.start?
11
- return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
11
+ return unless Bullet.n_plus_one_query_enable? || Bullet.unused_eager_loading_enable?
12
12
  return unless object.bullet_primary_key_value
13
13
 
14
14
  Bullet.debug(
@@ -21,7 +21,7 @@ module Bullet
21
21
 
22
22
  def add_call_object_associations(object, associations)
23
23
  return unless Bullet.start?
24
- return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
24
+ return unless Bullet.n_plus_one_query_enable? || Bullet.unused_eager_loading_enable?
25
25
  return unless object.bullet_primary_key_value
26
26
 
27
27
  Bullet.debug(
@@ -13,13 +13,19 @@ module Bullet
13
13
  # first, it keeps this method call for object.association.
14
14
  # then, it checks if this associations call is unpreload.
15
15
  # if it is, keeps this unpreload associations and caller.
16
- def call_association(object, associations)
16
+ def call_association(object, associations, caller_stack = nil, inversed: false)
17
17
  return unless Bullet.start?
18
- return unless Bullet.n_plus_one_query_enable?
18
+ return unless Bullet.n_plus_one_query_enable? || Bullet.unused_eager_loading_enable?
19
19
  return unless object.bullet_primary_key_value
20
- return if inversed_objects.include?(object.bullet_key, associations)
21
20
 
21
+ # Record before early-returns so legitimate reads that bypass SQL
22
+ # (inversed, nil-polymorphic) aren't flagged as unused preloads.
22
23
  add_call_object_associations(object, associations)
24
+ call_stacks.add(object.bullet_key, caller_stack) if caller_stack
25
+
26
+ return if inversed
27
+ return if inversed_objects.include?(object.bullet_key, associations)
28
+ return if optional_polymorphic_belongs_to_with_nil_type?(object, associations)
23
29
 
24
30
  Bullet.debug(
25
31
  'Detector::NPlusOneQuery#call_association',
@@ -115,6 +121,19 @@ module Bullet
115
121
 
116
122
  private
117
123
 
124
+ def optional_polymorphic_belongs_to_with_nil_type?(object, associations)
125
+ return false unless associations.is_a?(Symbol) || associations.is_a?(String)
126
+ return false unless object.class.respond_to?(:reflect_on_association)
127
+
128
+ reflection = object.class.reflect_on_association(associations.to_sym)
129
+ return false unless reflection
130
+ return false unless reflection.respond_to?(:polymorphic?) && reflection.polymorphic?
131
+ return false unless reflection.respond_to?(:foreign_type)
132
+
133
+ foreign_type = reflection.foreign_type
134
+ foreign_type && object.respond_to?(:[]) && object[foreign_type].nil?
135
+ end
136
+
118
137
  def create_notification(callers, klazz, associations)
119
138
  notify_associations = Array.wrap(associations) - Bullet.get_safelist_associations(:n_plus_one_query, klazz)
120
139
 
@@ -50,7 +50,7 @@ module Bullet
50
50
  if key_objects_overlap == k
51
51
  to_add << [k, associations]
52
52
  else
53
- to_merge << [key_objects_overlap, (eager_loadings[k].dup << associations)]
53
+ to_merge << [key_objects_overlap, eager_loadings[k].dup.merge(Array.wrap(associations))]
54
54
 
55
55
  keys_without_objects = k - key_objects_overlap
56
56
  to_merge << [keys_without_objects, eager_loadings[k]]
@@ -46,6 +46,8 @@ module Bullet
46
46
  ::Mongoid::Relations::Accessors.class_eval do
47
47
  alias_method :origin_get_relation, :get_relation
48
48
 
49
+ private
50
+
49
51
  def get_relation(name, metadata, object, reload = false)
50
52
  result = origin_get_relation(name, metadata, object, reload)
51
53
  Bullet::Detector::NPlusOneQuery.call_association(self, name) if metadata.macro !~ /embed/
@@ -46,6 +46,8 @@ module Bullet
46
46
  ::Mongoid::Relations::Accessors.class_eval do
47
47
  alias_method :origin_get_relation, :get_relation
48
48
 
49
+ private
50
+
49
51
  def get_relation(name, metadata, object, reload = false)
50
52
  result = origin_get_relation(name, metadata, object, reload)
51
53
  Bullet::Detector::NPlusOneQuery.call_association(self, name) if metadata.macro !~ /embed/
@@ -46,6 +46,8 @@ module Bullet
46
46
  ::Mongoid::Relations::Accessors.class_eval do
47
47
  alias_method :origin_get_relation, :get_relation
48
48
 
49
+ private
50
+
49
51
  def get_relation(name, metadata, object, reload = false)
50
52
  result = origin_get_relation(name, metadata, object, reload)
51
53
  Bullet::Detector::NPlusOneQuery.call_association(self, name) if metadata.macro !~ /embed/
@@ -61,6 +61,8 @@ module Bullet
61
61
  ::Mongoid::Association::Accessors.class_eval do
62
62
  alias_method :origin_get_relation, :get_relation
63
63
 
64
+ private
65
+
64
66
  def get_relation(name, association, object, reload = false)
65
67
  result = origin_get_relation(name, association, object, reload)
66
68
  Bullet::Detector::NPlusOneQuery.call_association(self, name) unless association.embedded?
@@ -46,6 +46,8 @@ module Bullet
46
46
  ::Mongoid::Association::Accessors.class_eval do
47
47
  alias_method :origin_get_relation, :get_relation
48
48
 
49
+ private
50
+
49
51
  def get_relation(name, association, object, reload = false)
50
52
  result = origin_get_relation(name, association, object, reload)
51
53
  unless association.embedded?
@@ -61,6 +61,8 @@ module Bullet
61
61
  ::Mongoid::Association::Accessors.class_eval do
62
62
  alias_method :origin_get_relation, :get_relation
63
63
 
64
+ private
65
+
64
66
  def get_relation(name, association, object, reload = false)
65
67
  result = origin_get_relation(name, association, object, reload)
66
68
  Bullet::Detector::NPlusOneQuery.call_association(self, name) unless association.embedded?
data/lib/bullet/rack.rb CHANGED
@@ -76,8 +76,9 @@ module Bullet
76
76
 
77
77
  # Make footer styles work with ContentSecurityPolicy style-src as self
78
78
  def footer_style(nonce = nil)
79
+ position_css = footer_position_css
79
80
  css = <<~CSS
80
- details#bullet-footer {cursor: pointer; position: fixed; left: 0px; bottom: 0px; z-index: 9999; background: #fdf2f2; color: #9b1c1c; font-size: 12px; border-radius: 0px 8px 0px 0px; border: 1px solid #9b1c1c;}
81
+ details#bullet-footer {cursor: pointer; position: fixed; #{position_css}; z-index: 9999; background: #fdf2f2; color: #9b1c1c; font-size: 12px; #{footer_border_radius}; border: 1px solid #9b1c1c;}
81
82
  details#bullet-footer summary {font-weight: 600; padding: 2px 8px;}
82
83
  details#bullet-footer div {padding: 8px; border-top: 1px solid #9b1c1c;}
83
84
  CSS
@@ -88,6 +89,38 @@ module Bullet
88
89
  end
89
90
  end
90
91
 
92
+ private
93
+
94
+ def footer_position_css
95
+ case Bullet.footer_position
96
+ when 'bottom_left'
97
+ 'left: 0px; bottom: 0px'
98
+ when 'bottom_right'
99
+ 'right: 0px; bottom: 0px'
100
+ when 'top_left'
101
+ 'left: 0px; top: 0px'
102
+ when 'top_right'
103
+ 'right: 0px; top: 0px'
104
+ else
105
+ 'left: 0px; bottom: 0px'
106
+ end
107
+ end
108
+
109
+ def footer_border_radius
110
+ case Bullet.footer_position
111
+ when 'bottom_left'
112
+ 'border-radius: 0px 8px 0px 0px'
113
+ when 'bottom_right'
114
+ 'border-radius: 8px 0px 0px 0px'
115
+ when 'top_left'
116
+ 'border-radius: 0px 0px 8px 0px'
117
+ when 'top_right'
118
+ 'border-radius: 0px 0px 0px 8px'
119
+ else
120
+ 'border-radius: 0px 8px 0px 0px'
121
+ end
122
+ end
123
+
91
124
  def set_header(headers, header_name, header_array)
92
125
  # Many proxy applications such as Nginx and AWS ELB limit
93
126
  # the size a header to 8KB, so truncate the list of reports to
@@ -123,7 +156,7 @@ module Bullet
123
156
  end
124
157
 
125
158
  def html_request?(headers, response)
126
- headers['Content-Type']&.include?('text/html')
159
+ headers['Content-Type']&.include?('text/html') || false
127
160
  end
128
161
 
129
162
  def response_body(response)
@@ -4,8 +4,13 @@ module Bullet
4
4
  module Registry
5
5
  class CallStack < Base
6
6
  # remembers found association backtrace
7
- def add(key)
8
- @registry[key] ||= Thread.current.backtrace
7
+ # if backtrace is provided, it will be used and override any existing value
8
+ def add(key, backtrace = nil)
9
+ if backtrace
10
+ @registry[key] = backtrace
11
+ else
12
+ @registry[key] ||= Thread.current.backtrace
13
+ end
9
14
  end
10
15
  end
11
16
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bullet
4
- VERSION = '8.0.8'
4
+ VERSION = '8.2.0'
5
5
  end
data/lib/bullet.rb CHANGED
@@ -42,6 +42,7 @@ module Bullet
42
42
  :skip_html_injection
43
43
  attr_reader :safelist
44
44
  attr_accessor :add_footer,
45
+ :footer_position,
45
46
  :orm_patches_applied,
46
47
  :skip_http_headers,
47
48
  :always_append_html_body,
@@ -123,7 +124,7 @@ module Bullet
123
124
  end
124
125
 
125
126
  def get_safelist_associations(type, class_name)
126
- Array.wrap(@safelist[type][class_name])
127
+ Array.wrap(@safelist[type][class_name]).flat_map { |a| [a, a.to_s] }
127
128
  end
128
129
 
129
130
  def reset_safelist
@@ -188,6 +189,26 @@ module Bullet
188
189
  enable? && Thread.current.thread_variable_get(:bullet_start)
189
190
  end
190
191
 
192
+ def pause
193
+ Thread.current.thread_variable_set(:bullet_start, false)
194
+ end
195
+
196
+ def resume
197
+ Thread.current.thread_variable_set(:bullet_start, true)
198
+ end
199
+
200
+ def paused?
201
+ enable? && !Thread.current.thread_variable_get(:bullet_start)
202
+ end
203
+
204
+ def skip
205
+ bullet_was_started = start?
206
+ pause if bullet_was_started
207
+ yield
208
+ ensure
209
+ resume if bullet_was_started
210
+ end
211
+
191
212
  def notification_collector
192
213
  Thread.current.thread_variable_get(:bullet_notification_collector)
193
214
  end
@@ -259,6 +280,10 @@ module Bullet
259
280
  UniformNotifier.active_notifiers.include?(UniformNotifier::JavascriptConsole)
260
281
  end
261
282
 
283
+ def footer_position
284
+ @footer_position || 'bottom_left'
285
+ end
286
+
262
287
  def inject_into_page?
263
288
  return false if defined?(@skip_html_injection) && @skip_html_injection
264
289
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.8
4
+ version: 8.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
@@ -37,6 +37,34 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '1.11'
40
+ - !ruby/object:Gem::Dependency
41
+ name: ostruct
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: logger
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
40
68
  description: help to kill N+1 queries and unused eager loading.
41
69
  email:
42
70
  - flyerhzm@gmail.com
@@ -49,17 +77,11 @@ files:
49
77
  - README.md
50
78
  - lib/bullet.rb
51
79
  - lib/bullet/active_job.rb
52
- - lib/bullet/active_record4.rb
53
- - lib/bullet/active_record41.rb
54
- - lib/bullet/active_record42.rb
55
- - lib/bullet/active_record5.rb
56
- - lib/bullet/active_record52.rb
57
- - lib/bullet/active_record60.rb
58
- - lib/bullet/active_record61.rb
59
80
  - lib/bullet/active_record70.rb
60
81
  - lib/bullet/active_record71.rb
61
82
  - lib/bullet/active_record72.rb
62
83
  - lib/bullet/active_record80.rb
84
+ - lib/bullet/active_record81.rb
63
85
  - lib/bullet/bullet_xhr.js
64
86
  - lib/bullet/dependency.rb
65
87
  - lib/bullet/detector.rb
@@ -112,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
134
  - !ruby/object:Gem::Version
113
135
  version: 1.3.6
114
136
  requirements: []
115
- rubygems_version: 3.6.9
137
+ rubygems_version: 4.0.6
116
138
  specification_version: 4
117
139
  summary: help to kill N+1 queries and unused eager loading.
118
140
  test_files: []
@@ -1,199 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bullet
4
- module ActiveRecord
5
- def self.enable
6
- require 'active_record'
7
- ::ActiveRecord::Base.class_eval do
8
- class << self
9
- alias_method :origin_find_by_sql, :find_by_sql
10
- def find_by_sql(sql, binds = [])
11
- result = origin_find_by_sql(sql, binds)
12
- if Bullet.start?
13
- if result.is_a? Array
14
- if result.size > 1
15
- Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
16
- Bullet::Detector::CounterCache.add_possible_objects(result)
17
- elsif result.size == 1
18
- Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
19
- Bullet::Detector::CounterCache.add_impossible_object(result.first)
20
- end
21
- elsif result.is_a? ::ActiveRecord::Base
22
- Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
23
- Bullet::Detector::CounterCache.add_impossible_object(result)
24
- end
25
- end
26
- result
27
- end
28
- end
29
- end
30
-
31
- ::ActiveRecord::Relation.class_eval do
32
- alias_method :origin_to_a, :to_a
33
- # if select a collection of objects, then these objects have possible to cause N+1 query.
34
- # if select only one object, then the only one object has impossible to cause N+1 query.
35
- def to_a
36
- records = origin_to_a
37
- if Bullet.start?
38
- if records.size > 1
39
- Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
40
- Bullet::Detector::CounterCache.add_possible_objects(records)
41
- elsif records.size == 1
42
- Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
43
- Bullet::Detector::CounterCache.add_impossible_object(records.first)
44
- end
45
- end
46
- records
47
- end
48
- end
49
-
50
- ::ActiveRecord::Persistence.class_eval do
51
- def _create_record_with_bullet(*args)
52
- _create_record_without_bullet(*args).tap do
53
- Bullet::Detector::NPlusOneQuery.update_inversed_object(self)
54
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
55
- end
56
- end
57
- alias_method_chain :_create_record, :bullet
58
- end
59
-
60
- ::ActiveRecord::Associations::Preloader.class_eval do
61
- # include query for one to many associations.
62
- # keep this eager loadings.
63
- alias_method :origin_initialize, :initialize
64
- def initialize(records, associations, preload_scope = nil)
65
- origin_initialize(records, associations, preload_scope)
66
-
67
- if Bullet.start?
68
- records = [records].flatten.compact.uniq
69
- return if records.empty?
70
-
71
- records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
72
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
73
- end
74
- end
75
- end
76
-
77
- ::ActiveRecord::FinderMethods.class_eval do
78
- # add includes in scope
79
- alias_method :origin_find_with_associations, :find_with_associations
80
- def find_with_associations
81
- records = origin_find_with_associations
82
- if Bullet.start?
83
- associations = (eager_load_values + includes_values).uniq
84
- records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
85
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
86
- end
87
- records
88
- end
89
- end
90
-
91
- ::ActiveRecord::Associations::JoinDependency.class_eval do
92
- alias_method :origin_instantiate, :instantiate
93
- alias_method :origin_construct_association, :construct_association
94
-
95
- def instantiate(rows)
96
- @bullet_eager_loadings = {}
97
- records = origin_instantiate(rows)
98
-
99
- if Bullet.start?
100
- @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
101
- objects = eager_loadings_hash.keys
102
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
103
- end
104
- end
105
- records
106
- end
107
-
108
- # call join associations
109
- def construct_association(record, join, row)
110
- result = origin_construct_association(record, join, row)
111
-
112
- if Bullet.start?
113
- associations = [join.reflection.name]
114
- if join.reflection.nested?
115
- associations << join.reflection.through_reflection.name
116
- end
117
- associations.each do |association|
118
- Bullet::Detector::Association.add_object_associations(record, association)
119
- Bullet::Detector::NPlusOneQuery.call_association(record, association)
120
- @bullet_eager_loadings[record.class] ||= {}
121
- @bullet_eager_loadings[record.class][record] ||= Set.new
122
- @bullet_eager_loadings[record.class][record] << association
123
- end
124
- end
125
-
126
- result
127
- end
128
- end
129
-
130
- ::ActiveRecord::Associations::CollectionAssociation.class_eval do
131
- # call one to many associations
132
- alias_method :origin_load_target, :load_target
133
- def load_target
134
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start?
135
- origin_load_target
136
- end
137
-
138
- alias_method :origin_include?, :include?
139
- def include?(object)
140
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start?
141
- origin_include?(object)
142
- end
143
- end
144
-
145
- ::ActiveRecord::Associations::HasManyAssociation.class_eval do
146
- alias_method :origin_empty?, :empty?
147
- def empty?
148
- if Bullet.start? && !loaded? && !has_cached_counter?(@reflection)
149
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
150
- end
151
- origin_empty?
152
- end
153
- end
154
-
155
- ::ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
156
- alias_method :origin_empty?, :empty?
157
- def empty?
158
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start? && !loaded?
159
- origin_empty?
160
- end
161
- end
162
-
163
- ::ActiveRecord::Associations::SingularAssociation.class_eval do
164
- # call has_one and belongs_to associations
165
- alias_method :origin_reader, :reader
166
- def reader(force_reload = false)
167
- result = origin_reader(force_reload)
168
- if Bullet.start?
169
- unless @inversed
170
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
171
- Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
172
- end
173
- end
174
- result
175
- end
176
- end
177
-
178
- ::ActiveRecord::Associations::HasManyAssociation.class_eval do
179
- alias_method :origin_has_cached_counter?, :has_cached_counter?
180
-
181
- def has_cached_counter?(reflection = reflection())
182
- result = origin_has_cached_counter?(reflection)
183
- Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name) if Bullet.start? && !result
184
- result
185
- end
186
- end
187
-
188
- ::ActiveRecord::Associations::CollectionProxy.class_eval do
189
- def count(column_name = nil, options = {})
190
- if Bullet.start?
191
- Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
192
- Bullet::Detector::NPlusOneQuery.call_association(proxy_association.owner, proxy_association.reflection.name)
193
- end
194
- super(column_name, options)
195
- end
196
- end
197
- end
198
- end
199
- end