bullet 7.0.7 → 7.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -1
  3. data/README.md +3 -0
  4. data/lib/bullet/active_record4.rb +9 -0
  5. data/lib/bullet/active_record41.rb +9 -0
  6. data/lib/bullet/active_record42.rb +9 -0
  7. data/lib/bullet/active_record5.rb +11 -0
  8. data/lib/bullet/active_record52.rb +11 -0
  9. data/lib/bullet/active_record60.rb +11 -0
  10. data/lib/bullet/active_record61.rb +11 -0
  11. data/lib/bullet/active_record70.rb +19 -6
  12. data/lib/bullet/active_record71.rb +297 -0
  13. data/lib/bullet/dependency.rb +12 -0
  14. data/lib/bullet/detector/unused_eager_loading.rb +1 -1
  15. data/lib/bullet/mongoid8x.rb +59 -0
  16. data/lib/bullet/notification/counter_cache.rb +1 -1
  17. data/lib/bullet/rack.rb +1 -1
  18. data/lib/bullet/version.rb +1 -1
  19. data/lib/bullet.rb +5 -1
  20. metadata +7 -155
  21. data/.github/workflows/main.yml +0 -82
  22. data/.gitignore +0 -15
  23. data/.rspec +0 -2
  24. data/Gemfile +0 -24
  25. data/Gemfile.mongoid +0 -12
  26. data/Gemfile.mongoid-4.0 +0 -15
  27. data/Gemfile.mongoid-5.0 +0 -15
  28. data/Gemfile.mongoid-6.0 +0 -15
  29. data/Gemfile.mongoid-7.0 +0 -15
  30. data/Gemfile.rails-4.0 +0 -16
  31. data/Gemfile.rails-4.1 +0 -16
  32. data/Gemfile.rails-4.2 +0 -16
  33. data/Gemfile.rails-5.0 +0 -15
  34. data/Gemfile.rails-5.1 +0 -15
  35. data/Gemfile.rails-5.2 +0 -15
  36. data/Gemfile.rails-6.0 +0 -15
  37. data/Gemfile.rails-6.1 +0 -15
  38. data/Gemfile.rails-7.0 +0 -10
  39. data/Guardfile +0 -8
  40. data/Hacking.md +0 -75
  41. data/Rakefile +0 -51
  42. data/bullet.gemspec +0 -33
  43. data/perf/benchmark.rb +0 -118
  44. data/rails/init.rb +0 -3
  45. data/spec/bullet/detector/association_spec.rb +0 -28
  46. data/spec/bullet/detector/base_spec.rb +0 -10
  47. data/spec/bullet/detector/counter_cache_spec.rb +0 -58
  48. data/spec/bullet/detector/n_plus_one_query_spec.rb +0 -150
  49. data/spec/bullet/detector/unused_eager_loading_spec.rb +0 -126
  50. data/spec/bullet/ext/object_spec.rb +0 -44
  51. data/spec/bullet/ext/string_spec.rb +0 -15
  52. data/spec/bullet/notification/base_spec.rb +0 -94
  53. data/spec/bullet/notification/counter_cache_spec.rb +0 -14
  54. data/spec/bullet/notification/n_plus_one_query_spec.rb +0 -29
  55. data/spec/bullet/notification/unused_eager_loading_spec.rb +0 -18
  56. data/spec/bullet/notification_collector_spec.rb +0 -34
  57. data/spec/bullet/rack_spec.rb +0 -296
  58. data/spec/bullet/registry/association_spec.rb +0 -28
  59. data/spec/bullet/registry/base_spec.rb +0 -46
  60. data/spec/bullet/registry/object_spec.rb +0 -26
  61. data/spec/bullet/stack_trace_filter_spec.rb +0 -26
  62. data/spec/bullet_spec.rb +0 -136
  63. data/spec/integration/active_record/association_spec.rb +0 -822
  64. data/spec/integration/counter_cache_spec.rb +0 -68
  65. data/spec/integration/mongoid/association_spec.rb +0 -246
  66. data/spec/models/address.rb +0 -5
  67. data/spec/models/attachment.rb +0 -5
  68. data/spec/models/author.rb +0 -5
  69. data/spec/models/base_user.rb +0 -7
  70. data/spec/models/category.rb +0 -12
  71. data/spec/models/city.rb +0 -5
  72. data/spec/models/client.rb +0 -8
  73. data/spec/models/comment.rb +0 -8
  74. data/spec/models/company.rb +0 -5
  75. data/spec/models/country.rb +0 -5
  76. data/spec/models/deal.rb +0 -5
  77. data/spec/models/document.rb +0 -7
  78. data/spec/models/entry.rb +0 -5
  79. data/spec/models/firm.rb +0 -7
  80. data/spec/models/folder.rb +0 -4
  81. data/spec/models/group.rb +0 -4
  82. data/spec/models/mongoid/address.rb +0 -9
  83. data/spec/models/mongoid/category.rb +0 -10
  84. data/spec/models/mongoid/comment.rb +0 -9
  85. data/spec/models/mongoid/company.rb +0 -9
  86. data/spec/models/mongoid/entry.rb +0 -9
  87. data/spec/models/mongoid/post.rb +0 -14
  88. data/spec/models/mongoid/user.rb +0 -7
  89. data/spec/models/newspaper.rb +0 -5
  90. data/spec/models/page.rb +0 -4
  91. data/spec/models/person.rb +0 -5
  92. data/spec/models/pet.rb +0 -5
  93. data/spec/models/post.rb +0 -34
  94. data/spec/models/relationship.rb +0 -6
  95. data/spec/models/reply.rb +0 -5
  96. data/spec/models/role.rb +0 -7
  97. data/spec/models/student.rb +0 -5
  98. data/spec/models/submission.rb +0 -7
  99. data/spec/models/teacher.rb +0 -5
  100. data/spec/models/user.rb +0 -8
  101. data/spec/models/writer.rb +0 -4
  102. data/spec/spec_helper.rb +0 -97
  103. data/spec/support/bullet_ext.rb +0 -56
  104. data/spec/support/mongo_seed.rb +0 -59
  105. data/spec/support/rack_double.rb +0 -49
  106. data/spec/support/sqlite_seed.rb +0 -284
  107. data/test.sh +0 -15
  108. data/update.sh +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f47e147f5df074217ee7a65123f54a1918f98bde162c7d4bf1f76bffc9f15a6
4
- data.tar.gz: e05e48b96a5e68bfbcac63f4dce4601d717ec1a32ee83a5c45aad738e1bfc48b
3
+ metadata.gz: 3556ad95bac8e87086710acf1c5b7ea5aa8252ee83ab3b20dfb4ec9e06a06474
4
+ data.tar.gz: 5d3695f3e2ab1ff51232e56d056aaf994630d465f5902106ceef125a7c6426d9
5
5
  SHA512:
6
- metadata.gz: 87bf095754befedb8f1137ae039191807baa1f1bcadb09c923b4f1a6abd385e73e4143e50077358a8f7155e3bf367edb1b405e3b0b260c8de5dd572699b7bafc
7
- data.tar.gz: fd692ae67a1695ee4598b24d3cd030a7f091deb42f30df0f92085b3c54f765960c0b5eabaace7b306fadf8539b514fe77076cff825c27a292c5e36f56916646b
6
+ metadata.gz: 150e4ba5ae1900d1e50b87cfed8f325ff2615bbe613e908bc5e253d7072a0018869a6a67ca311a3f22cd190cadc87882e99700e0f9ae1e54277b64ddd0d2fe45
7
+ data.tar.gz: cf3c2bf147e67915dd46670a8cf2b77b90c236fddca56fe1663ff62d8bf10a1a10506ee54773a28b7759d892ed6ed7fcdd7e0952d6b67ec8074b5a66abce0a8f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## Next Release
2
2
 
3
+ ## 7.1.0 (10/06/2023)
4
+
5
+ * Support rails 7.1
6
+ * Alias `Bullet.enable?` to `enabled?`, and `Bullet.enable=` to `enabled=`
7
+ * Added `always_append_html_body` option, so the html snippet is always included even if there are no notifications
8
+ * Added detection of n+1 count queries from `count` method
9
+ * Changed the counter cache notification title to recommend using `size`
10
+
3
11
  ## 7.0.7 (03/01/2023)
4
12
 
5
13
  * Check `Rails.application.config.content_security_policy` before insert `Bullet::Rack`
@@ -97,7 +105,7 @@
97
105
 
98
106
  * Fix through reflection for rails 5.x
99
107
  * Fix false positive in after_save/after_create callbacks
100
- * Don't triger a preload error on "manual" preloads
108
+ * Don't trigger a preload error on "manual" preloads
101
109
  * Avoid Bullet from making extra queries in mongoid6
102
110
  * Support option for #first and #last on mongoid6.x
103
111
  * Fix duplicate logs in mongoid 4.x and 5.x version
data/README.md CHANGED
@@ -101,6 +101,7 @@ The code above will enable all of the Bullet notification systems:
101
101
  item is a line number, a Range of line numbers, or a (bare) method name, to exclude only particular lines in a file.
102
102
  * `Bullet.slack`: add notifications to slack
103
103
  * `Bullet.raise`: raise errors, useful for making your specs fail unless they have optimized queries
104
+ * `Bullet.always_append_html_body`: always append the html body even if no notifications are present. Note: `console` or `add_footer` must also be true. Useful for Single Page Applications where the initial page load might not have any notifications present.
104
105
 
105
106
 
106
107
  Bullet also allows you to disable any of its detectors.
@@ -119,6 +120,8 @@ Bullet.unused_eager_loading_enable = false
119
120
  Bullet.counter_cache_enable = false
120
121
  ```
121
122
 
123
+ Note: When calling `Bullet.enable`, all other detectors are reset to their defaults (`true`) and need reconfiguring.
124
+
122
125
  ## Safe list
123
126
 
124
127
  Sometimes Bullet may notify you of query problems you don't care to fix, or
@@ -176,6 +176,15 @@ module Bullet
176
176
  result
177
177
  end
178
178
  end
179
+
180
+ ::ActiveRecord::Associations::CollectionProxy.class_eval do
181
+ def count
182
+ if Bullet.start?
183
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
184
+ end
185
+ super
186
+ end
187
+ end
179
188
  end
180
189
  end
181
190
  end
@@ -168,6 +168,15 @@ module Bullet
168
168
  origin_count_records
169
169
  end
170
170
  end
171
+
172
+ ::ActiveRecord::Associations::CollectionProxy.class_eval do
173
+ def count
174
+ if Bullet.start?
175
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
176
+ end
177
+ super
178
+ end
179
+ end
171
180
  end
172
181
  end
173
182
  end
@@ -233,6 +233,15 @@ module Bullet
233
233
  origin_count_records
234
234
  end
235
235
  end
236
+
237
+ ::ActiveRecord::Associations::CollectionProxy.class_eval do
238
+ def count
239
+ if Bullet.start?
240
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
241
+ end
242
+ super
243
+ end
244
+ end
236
245
  end
237
246
  end
238
247
  end
@@ -260,6 +260,17 @@ module Bullet
260
260
  end
261
261
  end
262
262
  )
263
+
264
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
265
+ Module.new do
266
+ def count
267
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
268
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
269
+ end
270
+ super
271
+ end
272
+ end
273
+ )
263
274
  end
264
275
  end
265
276
  end
@@ -242,6 +242,17 @@ module Bullet
242
242
  end
243
243
  end
244
244
  )
245
+
246
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
247
+ Module.new do
248
+ def count
249
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
250
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
251
+ end
252
+ super
253
+ end
254
+ end
255
+ )
245
256
  end
246
257
  end
247
258
  end
@@ -269,6 +269,17 @@ module Bullet
269
269
  end
270
270
  end
271
271
  )
272
+
273
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
274
+ Module.new do
275
+ def count
276
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
277
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
278
+ end
279
+ super
280
+ end
281
+ end
282
+ )
272
283
  end
273
284
  end
274
285
  end
@@ -269,6 +269,17 @@ module Bullet
269
269
  end
270
270
  end
271
271
  )
272
+
273
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
274
+ Module.new do
275
+ def count
276
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
277
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
278
+ end
279
+ super
280
+ end
281
+ end
282
+ )
272
283
  end
273
284
  end
274
285
  end
@@ -91,16 +91,18 @@ module Bullet
91
91
 
92
92
  ::ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(
93
93
  Module.new do
94
- def preloaded_records
95
- if Bullet.start? && !defined?(@preloaded_records)
96
- source_preloaders.each do |source_preloader|
97
- reflection_name = source_preloader.send(:reflection).name
98
- source_preloader.send(:owners).each do |owner|
94
+ def source_preloaders
95
+ if Bullet.start? && !defined?(@source_preloaders)
96
+ preloaders = super
97
+ preloaders.each do |preloader|
98
+ reflection_name = preloader.send(:reflection).name
99
+ preloader.send(:owners).each do |owner|
99
100
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
100
101
  end
101
102
  end
103
+ else
104
+ super
102
105
  end
103
- super
104
106
  end
105
107
  end
106
108
  )
@@ -279,6 +281,17 @@ module Bullet
279
281
  end
280
282
  end
281
283
  )
284
+
285
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
286
+ Module.new do
287
+ def count
288
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
289
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
290
+ end
291
+ super
292
+ end
293
+ end
294
+ )
282
295
  end
283
296
  end
284
297
  end
@@ -0,0 +1,297 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bullet
4
+ module SaveWithBulletSupport
5
+ def _create_record(*)
6
+ super do
7
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
8
+ yield(self) if block_given?
9
+ end
10
+ end
11
+ end
12
+
13
+ module ActiveRecord
14
+ def self.enable
15
+ require 'active_record'
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)
32
+ end
33
+ end
34
+ result
35
+ end
36
+ end
37
+ )
38
+
39
+ ::ActiveRecord::Base.prepend(SaveWithBulletSupport)
40
+
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
56
+ end
57
+ end
58
+ result
59
+ end
60
+ end
61
+ )
62
+
63
+ ::ActiveRecord::Associations::Preloader::Batch.prepend(
64
+ Module.new do
65
+ def call
66
+ if Bullet.start?
67
+ @preloaders.each do |preloader|
68
+ preloader.records.each { |record| Bullet::Detector::Association.add_object_associations(record, preloader.associations) }
69
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(preloader.records, preloader.associations)
70
+ end
71
+ end
72
+ super
73
+ end
74
+ end
75
+ )
76
+
77
+ ::ActiveRecord::Associations::Preloader::Branch.prepend(
78
+ Module.new do
79
+ def preloaders_for_reflection(reflection, reflection_records)
80
+ if Bullet.start?
81
+ reflection_records.compact!
82
+ if reflection_records.first.class.name !~ /^HABTM_/
83
+ reflection_records.each { |record| Bullet::Detector::Association.add_object_associations(record, reflection.name) }
84
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(reflection_records, reflection.name)
85
+ end
86
+ end
87
+ super
88
+ end
89
+ end
90
+ )
91
+
92
+ ::ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(
93
+ Module.new do
94
+ def source_preloaders
95
+ if Bullet.start? && !defined?(@source_preloaders)
96
+ preloaders = super
97
+ preloaders.each do |preloader|
98
+ reflection_name = preloader.send(:reflection).name
99
+ preloader.send(:owners).each do |owner|
100
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
101
+ end
102
+ end
103
+ else
104
+ super
105
+ end
106
+ end
107
+ end
108
+ )
109
+
110
+ ::ActiveRecord::Associations::JoinDependency.prepend(
111
+ Module.new do
112
+ def instantiate(result_set, strict_loading_value, &block)
113
+ @bullet_eager_loadings = {}
114
+ records = super
115
+
116
+ if Bullet.start?
117
+ @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
118
+ objects = eager_loadings_hash.keys
119
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(
120
+ objects,
121
+ eager_loadings_hash[objects.first].to_a
122
+ )
123
+ end
124
+ end
125
+ records
126
+ end
127
+
128
+ def construct(ar_parent, parent, row, seen, model_cache, strict_loading_value)
129
+ if Bullet.start?
130
+ unless ar_parent.nil?
131
+ parent.children.each do |node|
132
+ key = aliases.column_alias(node, node.primary_key)
133
+ id = row[key]
134
+ next unless id.nil?
135
+
136
+ associations = node.reflection.name
137
+ Bullet::Detector::Association.add_object_associations(ar_parent, associations)
138
+ Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
139
+ @bullet_eager_loadings[ar_parent.class] ||= {}
140
+ @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
141
+ @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
142
+ end
143
+ end
144
+ end
145
+
146
+ super
147
+ end
148
+
149
+ # call join associations
150
+ def construct_model(record, node, row, model_cache, id, strict_loading_value)
151
+ result = super
152
+
153
+ if Bullet.start?
154
+ associations = node.reflection.name
155
+ Bullet::Detector::Association.add_object_associations(record, associations)
156
+ Bullet::Detector::NPlusOneQuery.call_association(record, associations)
157
+ @bullet_eager_loadings[record.class] ||= {}
158
+ @bullet_eager_loadings[record.class][record] ||= Set.new
159
+ @bullet_eager_loadings[record.class][record] << associations
160
+ end
161
+
162
+ result
163
+ end
164
+ end
165
+ )
166
+
167
+ ::ActiveRecord::Associations::Association.prepend(
168
+ Module.new do
169
+ def inversed_from(record)
170
+ if Bullet.start?
171
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
172
+ end
173
+ super
174
+ end
175
+
176
+ def inversed_from_queries(record)
177
+ if Bullet.start? && inversable?(record)
178
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
179
+ end
180
+ super
181
+ end
182
+ end
183
+ )
184
+
185
+ ::ActiveRecord::Associations::CollectionAssociation.prepend(
186
+ Module.new do
187
+ def load_target
188
+ records = super
189
+
190
+ if Bullet.start?
191
+ if is_a? ::ActiveRecord::Associations::ThroughAssociation
192
+ association = owner.association(reflection.through_reflection.name)
193
+ if association.loaded?
194
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
195
+ Array.wrap(association.target).each do |through_record|
196
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
197
+ end
198
+
199
+ if reflection.through_reflection != through_reflection
200
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
201
+ end
202
+ end
203
+ end
204
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
205
+ if records.first.class.name !~ /^HABTM_/
206
+ if records.size > 1
207
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
208
+ Bullet::Detector::CounterCache.add_possible_objects(records)
209
+ elsif records.size == 1
210
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
211
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
212
+ end
213
+ end
214
+ end
215
+ records
216
+ end
217
+
218
+ def empty?
219
+ if Bullet.start? && !reflection.has_cached_counter?
220
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
221
+ end
222
+ super
223
+ end
224
+
225
+ def include?(object)
226
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
227
+ super
228
+ end
229
+ end
230
+ )
231
+
232
+ ::ActiveRecord::Associations::SingularAssociation.prepend(
233
+ Module.new do
234
+ # call has_one and belongs_to associations
235
+ def reader
236
+ result = super
237
+
238
+ if Bullet.start?
239
+ if owner.class.name !~ /^HABTM_/
240
+ if is_a? ::ActiveRecord::Associations::ThroughAssociation
241
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
242
+ association = owner.association(reflection.through_reflection.name)
243
+ Array.wrap(association.target).each do |through_record|
244
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
245
+ end
246
+
247
+ if reflection.through_reflection != through_reflection
248
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
249
+ end
250
+ end
251
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
252
+
253
+ if Bullet::Detector::NPlusOneQuery.impossible?(owner)
254
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
255
+ else
256
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
257
+ end
258
+ end
259
+ end
260
+ result
261
+ end
262
+ end
263
+ )
264
+
265
+ ::ActiveRecord::Associations::HasManyAssociation.prepend(
266
+ Module.new do
267
+ def empty?
268
+ result = super
269
+ if Bullet.start? && !reflection.has_cached_counter?
270
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
271
+ end
272
+ result
273
+ end
274
+
275
+ def count_records
276
+ result = reflection.has_cached_counter?
277
+ if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
278
+ Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
279
+ end
280
+ super
281
+ end
282
+ end
283
+ )
284
+
285
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
286
+ Module.new do
287
+ def count
288
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
289
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
290
+ end
291
+ super
292
+ end
293
+ end
294
+ )
295
+ end
296
+ end
297
+ end
@@ -31,6 +31,8 @@ module Bullet
31
31
  'active_record61'
32
32
  elsif active_record70?
33
33
  'active_record70'
34
+ elsif active_record71?
35
+ 'active_record71'
34
36
  else
35
37
  raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
36
38
  end
@@ -48,6 +50,8 @@ module Bullet
48
50
  'mongoid6x'
49
51
  elsif mongoid7x?
50
52
  'mongoid7x'
53
+ elsif mongoid8x?
54
+ 'mongoid8x'
51
55
  else
52
56
  raise "Bullet does not support mongoid #{::Mongoid::VERSION} yet"
53
57
  end
@@ -106,6 +110,10 @@ module Bullet
106
110
  active_record7? && ::ActiveRecord::VERSION::MINOR == 0
107
111
  end
108
112
 
113
+ def active_record71?
114
+ active_record7? && ::ActiveRecord::VERSION::MINOR == 1
115
+ end
116
+
109
117
  def mongoid4x?
110
118
  mongoid? && ::Mongoid::VERSION =~ /\A4/
111
119
  end
@@ -121,5 +129,9 @@ module Bullet
121
129
  def mongoid7x?
122
130
  mongoid? && ::Mongoid::VERSION =~ /\A7/
123
131
  end
132
+
133
+ def mongoid8x?
134
+ mongoid? && ::Mongoid::VERSION =~ /\A8/
135
+ end
124
136
  end
125
137
  end
@@ -10,7 +10,7 @@ module Bullet
10
10
  # check if there are unused preload associations.
11
11
  # get related_objects from eager_loadings associated with object and associations
12
12
  # get call_object_association from associations of call_object_associations whose object is in related_objects
13
- # if association not in call_object_association, then the object => association - call_object_association is ununsed preload associations
13
+ # if association not in call_object_association, then the object => association - call_object_association is unused preload associations
14
14
  def check_unused_preload_associations
15
15
  return unless Bullet.start?
16
16
  return unless Bullet.unused_eager_loading_enable?
@@ -0,0 +1,59 @@
1
+
2
+ module Bullet
3
+ module Mongoid
4
+ def self.enable
5
+ require 'mongoid'
6
+ ::Mongoid::Contextual::Mongo.class_eval do
7
+ alias_method :origin_first, :first
8
+ alias_method :origin_last, :last
9
+ alias_method :origin_each, :each
10
+ alias_method :origin_eager_load, :eager_load
11
+
12
+ def first(opts = {})
13
+ result = origin_first(opts)
14
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
15
+ result
16
+ end
17
+
18
+ def last(opts = {})
19
+ result = origin_last(opts)
20
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
21
+ result
22
+ end
23
+
24
+ def each(&block)
25
+ return to_enum unless block_given?
26
+ records = []
27
+ origin_each { |record| records << record }
28
+ if records.length > 1
29
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
30
+ elsif records.size == 1
31
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
32
+ end
33
+ records.each(&block)
34
+ end
35
+
36
+ def eager_load(docs)
37
+ associations = criteria.inclusions.map(&:name)
38
+ docs.each do |doc|
39
+ Bullet::Detector::NPlusOneQuery.add_object_associations(doc, associations)
40
+ end
41
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(docs, associations)
42
+ origin_eager_load(docs)
43
+ end
44
+ end
45
+
46
+ ::Mongoid::Association::Accessors.class_eval do
47
+ alias_method :origin_get_relation, :get_relation
48
+
49
+ def get_relation(name, association, object, reload = false)
50
+ result = origin_get_relation(name, association, object, reload)
51
+ unless association.embedded?
52
+ Bullet::Detector::NPlusOneQuery.call_association(self, name)
53
+ end
54
+ result
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -8,7 +8,7 @@ module Bullet
8
8
  end
9
9
 
10
10
  def title
11
- 'Need Counter Cache'
11
+ 'Need Counter Cache with Active Record size'
12
12
  end
13
13
  end
14
14
  end
data/lib/bullet/rack.rb CHANGED
@@ -18,7 +18,7 @@ module Bullet
18
18
 
19
19
  response_body = nil
20
20
 
21
- if Bullet.notification?
21
+ if Bullet.notification? || Bullet.always_append_html_body
22
22
  if Bullet.inject_into_page? && !file?(headers) && !sse?(headers) && !empty?(response) && status == 200
23
23
  if html_request?(headers, response)
24
24
  response_body = response_body(response)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bullet
4
- VERSION = '7.0.7'
4
+ VERSION = '7.1.0'
5
5
  end
data/lib/bullet.rb CHANGED
@@ -40,7 +40,7 @@ module Bullet
40
40
  :stacktrace_excludes,
41
41
  :skip_html_injection
42
42
  attr_reader :safelist
43
- attr_accessor :add_footer, :orm_patches_applied, :skip_http_headers
43
+ attr_accessor :add_footer, :orm_patches_applied, :skip_http_headers, :always_append_html_body
44
44
 
45
45
  available_notifiers =
46
46
  UniformNotifier::AVAILABLE_NOTIFIERS.select { |notifier| notifier != :raise }.map { |notifier| "#{notifier}=" }
@@ -70,10 +70,14 @@ module Bullet
70
70
  end
71
71
  end
72
72
 
73
+ alias enabled= enable=
74
+
73
75
  def enable?
74
76
  !!@enable
75
77
  end
76
78
 
79
+ alias enabled? enable?
80
+
77
81
  # Rails.root might be nil if `railties` is a dependency on a project that does not use Rails
78
82
  def app_root
79
83
  @app_root ||= (defined?(::Rails.root) && !::Rails.root.nil? ? Rails.root.to_s : Dir.pwd).to_s