bullet 5.9.0 → 7.0.4

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.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/main.yml +82 -0
  3. data/CHANGELOG.md +72 -0
  4. data/Gemfile.rails-4.0 +1 -1
  5. data/Gemfile.rails-4.1 +1 -1
  6. data/Gemfile.rails-4.2 +1 -1
  7. data/Gemfile.rails-5.0 +1 -1
  8. data/Gemfile.rails-5.1 +1 -1
  9. data/Gemfile.rails-5.2 +1 -1
  10. data/Gemfile.rails-6.0 +15 -0
  11. data/Gemfile.rails-6.1 +15 -0
  12. data/Gemfile.rails-7.0 +10 -0
  13. data/MIT-LICENSE +1 -1
  14. data/README.md +59 -33
  15. data/lib/bullet/active_job.rb +13 -0
  16. data/lib/bullet/active_record4.rb +9 -32
  17. data/lib/bullet/active_record41.rb +8 -27
  18. data/lib/bullet/active_record42.rb +9 -24
  19. data/lib/bullet/active_record5.rb +190 -179
  20. data/lib/bullet/active_record52.rb +184 -169
  21. data/lib/bullet/active_record60.rb +274 -0
  22. data/lib/bullet/active_record61.rb +274 -0
  23. data/lib/bullet/active_record70.rb +277 -0
  24. data/lib/bullet/bullet_xhr.js +64 -0
  25. data/lib/bullet/dependency.rb +60 -36
  26. data/lib/bullet/detector/association.rb +26 -20
  27. data/lib/bullet/detector/counter_cache.rb +15 -11
  28. data/lib/bullet/detector/n_plus_one_query.rb +24 -14
  29. data/lib/bullet/detector/unused_eager_loading.rb +8 -5
  30. data/lib/bullet/ext/object.rb +4 -2
  31. data/lib/bullet/mongoid4x.rb +3 -7
  32. data/lib/bullet/mongoid5x.rb +3 -7
  33. data/lib/bullet/mongoid6x.rb +3 -7
  34. data/lib/bullet/mongoid7x.rb +34 -23
  35. data/lib/bullet/notification/base.rb +14 -18
  36. data/lib/bullet/notification/n_plus_one_query.rb +2 -4
  37. data/lib/bullet/notification/unused_eager_loading.rb +2 -4
  38. data/lib/bullet/notification.rb +2 -1
  39. data/lib/bullet/rack.rb +55 -27
  40. data/lib/bullet/stack_trace_filter.rb +11 -19
  41. data/lib/bullet/version.rb +1 -1
  42. data/lib/bullet.rb +68 -42
  43. data/lib/generators/bullet/install_generator.rb +22 -23
  44. data/perf/benchmark.rb +11 -14
  45. data/spec/bullet/detector/counter_cache_spec.rb +6 -6
  46. data/spec/bullet/detector/n_plus_one_query_spec.rb +8 -4
  47. data/spec/bullet/detector/unused_eager_loading_spec.rb +25 -8
  48. data/spec/bullet/ext/object_spec.rb +10 -5
  49. data/spec/bullet/notification/base_spec.rb +5 -7
  50. data/spec/bullet/notification/n_plus_one_query_spec.rb +16 -3
  51. data/spec/bullet/notification/unused_eager_loading_spec.rb +5 -1
  52. data/spec/bullet/rack_spec.rb +161 -11
  53. data/spec/bullet/registry/association_spec.rb +2 -2
  54. data/spec/bullet/registry/base_spec.rb +1 -1
  55. data/spec/bullet_spec.rb +25 -44
  56. data/spec/integration/active_record/association_spec.rb +115 -144
  57. data/spec/integration/counter_cache_spec.rb +14 -34
  58. data/spec/integration/mongoid/association_spec.rb +19 -33
  59. data/spec/models/attachment.rb +5 -0
  60. data/spec/models/deal.rb +5 -0
  61. data/spec/models/post.rb +2 -0
  62. data/spec/models/role.rb +7 -0
  63. data/spec/models/submission.rb +1 -0
  64. data/spec/models/user.rb +2 -0
  65. data/spec/spec_helper.rb +4 -10
  66. data/spec/support/bullet_ext.rb +8 -9
  67. data/spec/support/mongo_seed.rb +3 -16
  68. data/spec/support/sqlite_seed.rb +38 -0
  69. data/test.sh +3 -0
  70. metadata +21 -8
  71. data/.travis.yml +0 -12
@@ -5,7 +5,7 @@ module Bullet
5
5
  def self.enable
6
6
  require 'active_record'
7
7
  ::ActiveRecord::Base.class_eval do
8
- class <<self
8
+ class << self
9
9
  alias_method :origin_find_by_sql, :find_by_sql
10
10
  def find_by_sql(sql, binds = [])
11
11
  result = origin_find_by_sql(sql, binds)
@@ -30,6 +30,7 @@ module Bullet
30
30
 
31
31
  ::ActiveRecord::Relation.class_eval do
32
32
  alias_method :origin_to_a, :to_a
33
+
33
34
  # if select a collection of objects, then these objects have possible to cause N+1 query.
34
35
  # if select only one object, then the only one object has impossible to cause N+1 query.
35
36
  def to_a
@@ -51,9 +52,7 @@ module Bullet
51
52
 
52
53
  ::ActiveRecord::Persistence.class_eval do
53
54
  def _create_record_with_bullet(*args)
54
- _create_record_without_bullet(*args).tap do
55
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
56
- end
55
+ _create_record_without_bullet(*args).tap { Bullet::Detector::NPlusOneQuery.add_impossible_object(self) }
57
56
  end
58
57
  alias_method_chain :_create_record, :bullet
59
58
  end
@@ -65,9 +64,7 @@ module Bullet
65
64
  if Bullet.start?
66
65
  records.compact!
67
66
  if records.first.class.name !~ /^HABTM_/
68
- records.each do |record|
69
- Bullet::Detector::Association.add_object_associations(record, association)
70
- end
67
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, association) }
71
68
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
72
69
  end
73
70
  end
@@ -84,9 +81,7 @@ module Bullet
84
81
  records = origin_find_with_associations
85
82
  if Bullet.start?
86
83
  associations = (eager_load_values + includes_values).uniq
87
- records.each do |record|
88
- Bullet::Detector::Association.add_object_associations(record, associations)
89
- end
84
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
90
85
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
91
86
  end
92
87
  records
@@ -131,9 +126,7 @@ module Bullet
131
126
  # call one to many associations
132
127
  alias_method :origin_load_target, :load_target
133
128
  def load_target
134
- if Bullet.start?
135
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
136
- end
129
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start? && !@inversed
137
130
  origin_load_target
138
131
  end
139
132
 
@@ -147,9 +140,7 @@ module Bullet
147
140
 
148
141
  alias_method :origin_include?, :include?
149
142
  def include?(object)
150
- if Bullet.start?
151
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
152
- end
143
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start?
153
144
  origin_include?(object)
154
145
  end
155
146
  end
@@ -173,20 +164,10 @@ module Bullet
173
164
  alias_method :origin_count_records, :count_records
174
165
  def count_records
175
166
  result = has_cached_counter?
176
- if Bullet.start? && !result
177
- Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name)
178
- end
167
+ Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) if Bullet.start? && !result
179
168
  origin_count_records
180
169
  end
181
170
  end
182
-
183
- ::ActiveRecord::Associations::BelongsToAssociation.class_eval do
184
- def writer_with_bullet(record)
185
- Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
186
- writer_without_bullet(record)
187
- end
188
- alias_method_chain :writer, :bullet
189
- end
190
171
  end
191
172
  end
192
173
  end
@@ -5,7 +5,7 @@ module Bullet
5
5
  def self.enable
6
6
  require 'active_record'
7
7
  ::ActiveRecord::Base.class_eval do
8
- class <<self
8
+ class << self
9
9
  alias_method :origin_find, :find
10
10
  def find(*args)
11
11
  result = origin_find(*args)
@@ -45,15 +45,14 @@ module Bullet
45
45
 
46
46
  ::ActiveRecord::Persistence.class_eval do
47
47
  def _create_record_with_bullet(*args)
48
- _create_record_without_bullet(*args).tap do
49
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
50
- end
48
+ _create_record_without_bullet(*args).tap { Bullet::Detector::NPlusOneQuery.add_impossible_object(self) }
51
49
  end
52
50
  alias_method_chain :_create_record, :bullet
53
51
  end
54
52
 
55
53
  ::ActiveRecord::Relation.class_eval do
56
54
  alias_method :origin_to_a, :to_a
55
+
57
56
  # if select a collection of objects, then these objects have possible to cause N+1 query.
58
57
  # if select only one object, then the only one object has impossible to cause N+1 query.
59
58
  def to_a
@@ -80,9 +79,7 @@ module Bullet
80
79
  if Bullet.start?
81
80
  records.compact!
82
81
  if records.first.class.name !~ /^HABTM_/
83
- records.each do |record|
84
- Bullet::Detector::Association.add_object_associations(record, association)
85
- end
82
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, association) }
86
83
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
87
84
  end
88
85
  end
@@ -99,9 +96,7 @@ module Bullet
99
96
  records = origin_find_with_associations
100
97
  if Bullet.start?
101
98
  associations = (eager_load_values + includes_values).uniq
102
- records.each do |record|
103
- Bullet::Detector::Association.add_object_associations(record, associations)
104
- end
99
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
105
100
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
106
101
  end
107
102
  records
@@ -195,9 +190,7 @@ module Bullet
195
190
 
196
191
  alias_method :origin_include?, :include?
197
192
  def include?(object)
198
- if Bullet.start?
199
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
200
- end
193
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) if Bullet.start?
201
194
  origin_include?(object)
202
195
  end
203
196
  end
@@ -207,9 +200,11 @@ module Bullet
207
200
  alias_method :origin_reader, :reader
208
201
  def reader(force_reload = false)
209
202
  result = origin_reader(force_reload)
203
+
210
204
  if Bullet.start?
211
205
  if @owner.class.name !~ /^HABTM_/ && !@inversed
212
206
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
207
+
213
208
  if Bullet::Detector::NPlusOneQuery.impossible?(@owner)
214
209
  Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
215
210
  else
@@ -234,20 +229,10 @@ module Bullet
234
229
  alias_method :origin_count_records, :count_records
235
230
  def count_records
236
231
  result = has_cached_counter?
237
- if Bullet.start? && !result
238
- Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name)
239
- end
232
+ Bullet::Detector::CounterCache.add_counter_cache(@owner, @reflection.name) if Bullet.start? && !result
240
233
  origin_count_records
241
234
  end
242
235
  end
243
-
244
- ::ActiveRecord::Associations::BelongsToAssociation.class_eval do
245
- def writer_with_bullet(record)
246
- Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
247
- writer_without_bullet(record)
248
- end
249
- alias_method_chain :writer, :bullet
250
- end
251
236
  end
252
237
  end
253
238
  end
@@ -13,242 +13,253 @@ module Bullet
13
13
  module ActiveRecord
14
14
  def self.enable
15
15
  require 'active_record'
16
- ::ActiveRecord::Base.extend(Module.new do
17
- def find_by_sql(sql, binds = [], preparable: nil, &block)
18
- result = super
19
- if Bullet.start?
20
- if result.is_a? Array
21
- if result.size > 1
22
- Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
23
- Bullet::Detector::CounterCache.add_possible_objects(result)
24
- elsif result.size == 1
25
- Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
26
- Bullet::Detector::CounterCache.add_impossible_object(result.first)
16
+ ::ActiveRecord::Base.extend(
17
+ Module.new do
18
+ def find_by_sql(sql, binds = [], preparable: nil, &block)
19
+ result = super
20
+ if Bullet.start?
21
+ if result.is_a? Array
22
+ if result.size > 1
23
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
24
+ Bullet::Detector::CounterCache.add_possible_objects(result)
25
+ elsif result.size == 1
26
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
27
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
28
+ end
29
+ elsif result.is_a? ::ActiveRecord::Base
30
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
31
+ Bullet::Detector::CounterCache.add_impossible_object(result)
27
32
  end
28
- elsif result.is_a? ::ActiveRecord::Base
29
- Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
30
- Bullet::Detector::CounterCache.add_impossible_object(result)
31
33
  end
34
+ result
32
35
  end
33
- result
34
36
  end
35
- end)
37
+ )
36
38
 
37
39
  ::ActiveRecord::Base.prepend(SaveWithBulletSupport)
38
40
 
39
- ::ActiveRecord::Relation.prepend(Module.new do
40
- # if select a collection of objects, then these objects have possible to cause N+1 query.
41
- # if select only one object, then the only one object has impossible to cause N+1 query.
42
- def records
43
- result = super
44
- if Bullet.start?
45
- if result.first.class.name !~ /^HABTM_/
46
- if result.size > 1
47
- Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
48
- Bullet::Detector::CounterCache.add_possible_objects(result)
49
- elsif result.size == 1
50
- Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
51
- Bullet::Detector::CounterCache.add_impossible_object(result.first)
41
+ ::ActiveRecord::Relation.prepend(
42
+ Module.new do
43
+ # if select a collection of objects, then these objects have possible to cause N+1 query.
44
+ # if select only one object, then the only one object has impossible to cause N+1 query.
45
+ def records
46
+ result = super
47
+ if Bullet.start?
48
+ if result.first.class.name !~ /^HABTM_/
49
+ if result.size > 1
50
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
51
+ Bullet::Detector::CounterCache.add_possible_objects(result)
52
+ elsif result.size == 1
53
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
54
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
55
+ end
52
56
  end
53
57
  end
58
+ result
54
59
  end
55
- result
56
60
  end
57
- end)
58
-
59
- ::ActiveRecord::Associations::Preloader.prepend(Module.new do
60
- def preloaders_for_one(association, records, scope)
61
- if Bullet.start?
62
- records.compact!
63
- if records.first.class.name !~ /^HABTM_/
64
- records.each do |record|
65
- Bullet::Detector::Association.add_object_associations(record, association)
61
+ )
62
+
63
+ ::ActiveRecord::Associations::Preloader.prepend(
64
+ Module.new do
65
+ def preloaders_for_one(association, records, scope)
66
+ if Bullet.start?
67
+ records.compact!
68
+ if records.first.class.name !~ /^HABTM_/
69
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, association) }
70
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
66
71
  end
67
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
68
72
  end
73
+ super
69
74
  end
70
- super
71
75
  end
72
- end)
76
+ )
73
77
 
74
- ::ActiveRecord::FinderMethods.prepend(Module.new do
75
- # add includes in scope
76
- def find_with_associations
77
- return super { |r| yield r } if block_given?
78
+ ::ActiveRecord::FinderMethods.prepend(
79
+ Module.new do
80
+ # add includes in scope
81
+ def find_with_associations
82
+ return super { |r| yield r } if block_given?
78
83
 
79
- records = super
80
- if Bullet.start?
81
- associations = (eager_load_values + includes_values).uniq
82
- records.each do |record|
83
- Bullet::Detector::Association.add_object_associations(record, associations)
84
+ records = super
85
+ if Bullet.start?
86
+ associations = (eager_load_values + includes_values).uniq
87
+ records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
88
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
84
89
  end
85
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
90
+ records
86
91
  end
87
- records
88
92
  end
89
- end)
93
+ )
90
94
 
91
- ::ActiveRecord::Associations::JoinDependency.prepend(Module.new do
92
- if ::ActiveRecord::Associations::JoinDependency.instance_method(:instantiate).parameters.last[0] == :block
93
- # ActiveRecord >= 5.1.5
94
- def instantiate(result_set, &block)
95
- @bullet_eager_loadings = {}
96
- records = super
95
+ ::ActiveRecord::Associations::JoinDependency.prepend(
96
+ Module.new do
97
+ if ::ActiveRecord::Associations::JoinDependency.instance_method(:instantiate).parameters.last[0] == :block
98
+ # ActiveRecord >= 5.1.5
99
+ def instantiate(result_set, &block)
100
+ @bullet_eager_loadings = {}
101
+ records = super
97
102
 
98
- if Bullet.start?
99
- @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
100
- objects = eager_loadings_hash.keys
101
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
103
+ if Bullet.start?
104
+ @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
105
+ objects = eager_loadings_hash.keys
106
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(
107
+ objects,
108
+ eager_loadings_hash[objects.first].to_a
109
+ )
110
+ end
102
111
  end
112
+ records
103
113
  end
104
- records
105
- end
106
- else
107
- # ActiveRecord <= 5.1.4
108
- def instantiate(result_set, aliases)
109
- @bullet_eager_loadings = {}
110
- records = super
114
+ else
115
+ # ActiveRecord <= 5.1.4
116
+ def instantiate(result_set, aliases)
117
+ @bullet_eager_loadings = {}
118
+ records = super
111
119
 
112
- if Bullet.start?
113
- @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
114
- objects = eager_loadings_hash.keys
115
- Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
120
+ if Bullet.start?
121
+ @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
122
+ objects = eager_loadings_hash.keys
123
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(
124
+ objects,
125
+ eager_loadings_hash[objects.first].to_a
126
+ )
127
+ end
116
128
  end
129
+ records
117
130
  end
118
- records
119
131
  end
120
- end
121
132
 
122
- def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
123
- if Bullet.start?
124
- unless ar_parent.nil?
125
- parent.children.each do |node|
126
- key = aliases.column_alias(node, node.primary_key)
127
- id = row[key]
128
- next unless id.nil?
129
-
130
- associations = node.reflection.name
131
- Bullet::Detector::Association.add_object_associations(ar_parent, associations)
132
- Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
133
- @bullet_eager_loadings[ar_parent.class] ||= {}
134
- @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
135
- @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
133
+ def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
134
+ if Bullet.start?
135
+ unless ar_parent.nil?
136
+ parent.children.each do |node|
137
+ key = aliases.column_alias(node, node.primary_key)
138
+ id = row[key]
139
+ next unless id.nil?
140
+
141
+ associations = node.reflection.name
142
+ Bullet::Detector::Association.add_object_associations(ar_parent, associations)
143
+ Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
144
+ @bullet_eager_loadings[ar_parent.class] ||= {}
145
+ @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
146
+ @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
147
+ end
136
148
  end
137
149
  end
150
+
151
+ super
138
152
  end
139
153
 
140
- super
141
- end
154
+ # call join associations
155
+ def construct_model(record, node, row, model_cache, id, aliases)
156
+ result = super
142
157
 
143
- # call join associations
144
- def construct_model(record, node, row, model_cache, id, aliases)
145
- result = super
146
-
147
- if Bullet.start?
148
- associations = node.reflection.name
149
- Bullet::Detector::Association.add_object_associations(record, associations)
150
- Bullet::Detector::NPlusOneQuery.call_association(record, associations)
151
- @bullet_eager_loadings[record.class] ||= {}
152
- @bullet_eager_loadings[record.class][record] ||= Set.new
153
- @bullet_eager_loadings[record.class][record] << associations
154
- end
158
+ if Bullet.start?
159
+ associations = node.reflection.name
160
+ Bullet::Detector::Association.add_object_associations(record, associations)
161
+ Bullet::Detector::NPlusOneQuery.call_association(record, associations)
162
+ @bullet_eager_loadings[record.class] ||= {}
163
+ @bullet_eager_loadings[record.class][record] ||= Set.new
164
+ @bullet_eager_loadings[record.class][record] << associations
165
+ end
155
166
 
156
- result
167
+ result
168
+ end
157
169
  end
158
- end)
159
-
160
- ::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new do
161
- def load_target
162
- records = super
163
-
164
- if Bullet.start?
165
- if is_a? ::ActiveRecord::Associations::ThroughAssociation
166
- refl = reflection.through_reflection
167
- Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
168
- association = owner.association refl.name
169
- Array(association.target).each do |through_record|
170
- Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
171
- end
170
+ )
172
171
 
173
- if refl.through_reflection?
174
- while refl.through_reflection?
175
- refl = refl.through_reflection
172
+ ::ActiveRecord::Associations::CollectionAssociation.prepend(
173
+ Module.new do
174
+ def load_target
175
+ records = super
176
+
177
+ if Bullet.start?
178
+ if is_a? ::ActiveRecord::Associations::ThroughAssociation
179
+ refl = reflection.through_reflection
180
+ association = owner.association(refl.name)
181
+ if association.loaded?
182
+ Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
183
+ Array.wrap(association.target).each do |through_record|
184
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
185
+ end
176
186
  end
177
187
 
178
- Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
188
+ if refl.through_reflection?
189
+ refl = refl.through_reflection while refl.through_reflection?
190
+
191
+ Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
192
+ end
179
193
  end
180
- end
181
- Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
182
- if records.first.class.name !~ /^HABTM_/
183
- if records.size > 1
184
- Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
185
- Bullet::Detector::CounterCache.add_possible_objects(records)
186
- elsif records.size == 1
187
- Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
188
- Bullet::Detector::CounterCache.add_impossible_object(records.first)
194
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
195
+ if records.first.class.name !~ /^HABTM_/
196
+ if records.size > 1
197
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
198
+ Bullet::Detector::CounterCache.add_possible_objects(records)
199
+ elsif records.size == 1
200
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
201
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
202
+ end
189
203
  end
190
204
  end
205
+ records
191
206
  end
192
- records
193
- end
194
207
 
195
- def empty?
196
- if Bullet.start? && !reflection.has_cached_counter?
197
- Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
208
+ def empty?
209
+ if Bullet.start? && !reflection.has_cached_counter?
210
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
211
+ end
212
+ super
198
213
  end
199
- super
200
- end
201
214
 
202
- def include?(object)
203
- if Bullet.start?
204
- Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
215
+ def include?(object)
216
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
217
+ super
205
218
  end
206
- super
207
219
  end
208
- end)
209
-
210
- ::ActiveRecord::Associations::SingularAssociation.prepend(Module.new do
211
- # call has_one and belongs_to associations
212
- def target
213
- result = super()
214
- if Bullet.start?
215
- if owner.class.name !~ /^HABTM_/ && !@inversed
216
- Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
217
- if Bullet::Detector::NPlusOneQuery.impossible?(owner)
218
- Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
219
- else
220
- Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
220
+ )
221
+
222
+ ::ActiveRecord::Associations::SingularAssociation.prepend(
223
+ Module.new do
224
+ # call has_one and belongs_to associations
225
+ def target
226
+ result = super()
227
+
228
+ if Bullet.start?
229
+ if owner.class.name !~ /^HABTM_/ && !@inversed
230
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
231
+
232
+ if Bullet::Detector::NPlusOneQuery.impossible?(owner)
233
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
234
+ else
235
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
236
+ end
221
237
  end
222
238
  end
239
+ result
223
240
  end
224
- result
225
241
  end
226
- end)
242
+ )
227
243
 
228
- ::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new do
229
- def empty?
230
- result = super
231
- if Bullet.start? && !reflection.has_cached_counter?
232
- Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
244
+ ::ActiveRecord::Associations::HasManyAssociation.prepend(
245
+ Module.new do
246
+ def empty?
247
+ result = super
248
+ if Bullet.start? && !reflection.has_cached_counter?
249
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
250
+ end
251
+ result
233
252
  end
234
- result
235
- end
236
253
 
237
- def count_records
238
- result = reflection.has_cached_counter?
239
- if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
240
- Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
254
+ def count_records
255
+ result = reflection.has_cached_counter?
256
+ if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
257
+ Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
258
+ end
259
+ super
241
260
  end
242
- super
243
- end
244
- end)
245
-
246
- ::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
247
- def writer(record)
248
- Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
249
- super
250
261
  end
251
- end)
262
+ )
252
263
  end
253
264
  end
254
265
  end