bullet 8.2.0 → 8.3.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -1
- data/lib/bullet/active_record82.rb +335 -0
- data/lib/bullet/dependency.rb +6 -0
- data/lib/bullet/detector/association.rb +7 -7
- data/lib/bullet/detector/counter_cache.rb +2 -2
- data/lib/bullet/rack.rb +6 -1
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +47 -32
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d5c5aff8226198c501ed0c0a3e9d71138bd896f9956cf072b0f92fef79b125c7
|
|
4
|
+
data.tar.gz: 90209fe95da7ad96e110cfdabb96a91a9c403ef9e5824df2877aeab20239f020
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 98dbc38b0e5f77f61617e75bab2b92838bbead761421681791711c917f61282e6ae29fe70fabe645ef8685344a879535fb4634451ff1bb35d560b0fd8a9c3a12
|
|
7
|
+
data.tar.gz: 49f2ebf88e0d99386ebd35a82403ece35167e9ac253013244f9ded4fe76de6b14ea070741847b6048b90ca1e15b6765430a56a180d8f6e6961383be035d08b38
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
## 8.3.1 (10/24/2026)
|
|
4
|
+
|
|
5
|
+
* Avoid redefining the `footer_position` getter
|
|
6
|
+
* Avoid the CGI loading warning on Ruby 4
|
|
7
|
+
* Keep request state separate for sibling fibers on one thread
|
|
8
|
+
|
|
9
|
+
## 8.3.0 (10/10/2026)
|
|
10
|
+
|
|
11
|
+
* Add support for ActiveRecord 8.2
|
|
12
|
+
|
|
3
13
|
## 8.2.0 (08/29/2026)
|
|
4
14
|
|
|
5
15
|
* Add thread-safe `Bullet.pause`, `Bullet.resume`, `Bullet.paused?`, and `Bullet.skip` APIs
|
|
@@ -11,7 +21,7 @@
|
|
|
11
21
|
|
|
12
22
|
## 8.1.3 (06/02/2026)
|
|
13
23
|
|
|
14
|
-
* Handle inversed polymorphic belongs_to false positives
|
|
24
|
+
* Handle inversed polymorphic `belongs_to` false positives
|
|
15
25
|
|
|
16
26
|
## 8.1.2 (05/25/2026)
|
|
17
27
|
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bullet
|
|
4
|
+
module SaveWithBulletSupport
|
|
5
|
+
def _create_record(*)
|
|
6
|
+
super do
|
|
7
|
+
Bullet::Detector::NPlusOneQuery.update_inversed_object(self)
|
|
8
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
|
9
|
+
yield(self) if block_given?
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module ActiveRecord
|
|
15
|
+
def self.enable
|
|
16
|
+
require 'active_record'
|
|
17
|
+
::ActiveRecord::Base.extend(
|
|
18
|
+
Module.new do
|
|
19
|
+
def find_by_sql(*args, **kwargs, &block)
|
|
20
|
+
result = super(*args, **kwargs, &block)
|
|
21
|
+
if Bullet.start?
|
|
22
|
+
if result.is_a? Array
|
|
23
|
+
if result.size > 1
|
|
24
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
|
25
|
+
Bullet::Detector::CounterCache.add_possible_objects(result)
|
|
26
|
+
elsif result.size == 1
|
|
27
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
|
|
28
|
+
Bullet::Detector::CounterCache.add_impossible_object(result.first)
|
|
29
|
+
end
|
|
30
|
+
elsif result.is_a? ::ActiveRecord::Base
|
|
31
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
|
|
32
|
+
Bullet::Detector::CounterCache.add_impossible_object(result)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
result
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
::ActiveRecord::Base.prepend(SaveWithBulletSupport)
|
|
41
|
+
|
|
42
|
+
::ActiveRecord::Relation.prepend(
|
|
43
|
+
Module.new do
|
|
44
|
+
# if select a collection of objects, then these objects have possible to cause N+1 query.
|
|
45
|
+
# if select only one object, then the only one object has impossible to cause N+1 query.
|
|
46
|
+
def records
|
|
47
|
+
result = super
|
|
48
|
+
if Bullet.start?
|
|
49
|
+
if result.first.class.name !~ /^HABTM_/
|
|
50
|
+
if result.size > 1
|
|
51
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
|
52
|
+
Bullet::Detector::CounterCache.add_possible_objects(result)
|
|
53
|
+
elsif result.size == 1
|
|
54
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
|
|
55
|
+
Bullet::Detector::CounterCache.add_impossible_object(result.first)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
result
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
::ActiveRecord::Associations::Preloader::Batch.prepend(
|
|
65
|
+
Module.new do
|
|
66
|
+
def call
|
|
67
|
+
if Bullet.start?
|
|
68
|
+
@preloaders.each do |preloader|
|
|
69
|
+
preloader.records.each { |record|
|
|
70
|
+
Bullet::Detector::Association.add_object_associations(record, preloader.associations)
|
|
71
|
+
}
|
|
72
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(preloader.records, preloader.associations)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
super
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
::ActiveRecord::Associations::Preloader::Branch.prepend(
|
|
81
|
+
Module.new do
|
|
82
|
+
def preloaders_for_reflection(reflection, reflection_records)
|
|
83
|
+
if Bullet.start?
|
|
84
|
+
reflection_records.compact!
|
|
85
|
+
if reflection_records.first.class.name !~ /^HABTM_/
|
|
86
|
+
reflection_records.each { |record|
|
|
87
|
+
Bullet::Detector::Association.add_object_associations(record, reflection.name)
|
|
88
|
+
}
|
|
89
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(reflection_records, reflection.name)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
super
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
::ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(
|
|
98
|
+
Module.new do
|
|
99
|
+
def source_preloaders
|
|
100
|
+
if Bullet.start? && !defined?(@source_preloaders)
|
|
101
|
+
preloaders = super
|
|
102
|
+
preloaders.each do |preloader|
|
|
103
|
+
reflection_name = preloader.send(:reflection).name
|
|
104
|
+
preloader.send(:owners).each do |owner|
|
|
105
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
else
|
|
109
|
+
super
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def through_preloaders
|
|
114
|
+
if Bullet.start? && !defined?(@through_preloaders)
|
|
115
|
+
preloaders = super
|
|
116
|
+
preloaders.each do |preloader|
|
|
117
|
+
reflection_name = preloader.send(:reflection).name
|
|
118
|
+
preloader.send(:owners).each do |owner|
|
|
119
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
else
|
|
123
|
+
super
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
::ActiveRecord::Associations::JoinDependency.prepend(
|
|
130
|
+
Module.new do
|
|
131
|
+
def instantiate(*args, **kwargs, &block)
|
|
132
|
+
@bullet_eager_loadings = {}
|
|
133
|
+
records = super(*args, **kwargs, &block)
|
|
134
|
+
|
|
135
|
+
if Bullet.start?
|
|
136
|
+
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
|
137
|
+
objects = eager_loadings_hash.keys
|
|
138
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(
|
|
139
|
+
objects,
|
|
140
|
+
eager_loadings_hash[objects.first].to_a
|
|
141
|
+
)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
records
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def construct(*args, **kwargs, &block)
|
|
148
|
+
ar_parent, parent, row = args
|
|
149
|
+
if Bullet.start?
|
|
150
|
+
unless ar_parent.nil?
|
|
151
|
+
parent.children.each do |node|
|
|
152
|
+
key = aliases.column_alias(node, node.primary_key)
|
|
153
|
+
id = row[key]
|
|
154
|
+
next unless id.nil?
|
|
155
|
+
|
|
156
|
+
associations = [node.reflection.name]
|
|
157
|
+
if node.reflection.through_reflection?
|
|
158
|
+
associations << node.reflection.through_reflection.name
|
|
159
|
+
end
|
|
160
|
+
associations.each do |association|
|
|
161
|
+
Bullet::Detector::Association.add_object_associations(ar_parent, association)
|
|
162
|
+
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, association)
|
|
163
|
+
@bullet_eager_loadings[ar_parent.class] ||= {}
|
|
164
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
|
|
165
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] << association
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
super(*args, **kwargs, &block)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# call join associations
|
|
175
|
+
def construct_model(*args, **kwargs, &block)
|
|
176
|
+
record, node = args
|
|
177
|
+
result = super(*args, **kwargs, &block)
|
|
178
|
+
|
|
179
|
+
if Bullet.start?
|
|
180
|
+
associations = [node.reflection.name]
|
|
181
|
+
if node.reflection.through_reflection?
|
|
182
|
+
associations << node.reflection.through_reflection.name
|
|
183
|
+
end
|
|
184
|
+
associations.each do |association|
|
|
185
|
+
Bullet::Detector::Association.add_object_associations(record, association)
|
|
186
|
+
Bullet::Detector::NPlusOneQuery.call_association(record, association)
|
|
187
|
+
@bullet_eager_loadings[record.class] ||= {}
|
|
188
|
+
@bullet_eager_loadings[record.class][record] ||= Set.new
|
|
189
|
+
@bullet_eager_loadings[record.class][record] << association
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
result
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
::ActiveRecord::Associations::Association.prepend(
|
|
199
|
+
Module.new do
|
|
200
|
+
def inversed_from(record)
|
|
201
|
+
if Bullet.start?
|
|
202
|
+
Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
|
|
203
|
+
end
|
|
204
|
+
super
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def inversed_from_queries(record)
|
|
208
|
+
if Bullet.start? && inversable?(record)
|
|
209
|
+
Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
|
|
210
|
+
end
|
|
211
|
+
super
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
::ActiveRecord::Associations::CollectionAssociation.prepend(
|
|
217
|
+
Module.new do
|
|
218
|
+
def load_target
|
|
219
|
+
records = super
|
|
220
|
+
|
|
221
|
+
if Bullet.start?
|
|
222
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
|
223
|
+
association = owner.association(reflection.through_reflection.name)
|
|
224
|
+
if association.loaded?
|
|
225
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
|
226
|
+
Array.wrap(association.target).each do |through_record|
|
|
227
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
if reflection.through_reflection != through_reflection
|
|
231
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
236
|
+
if records.first.class.name !~ /^HABTM_/
|
|
237
|
+
if records.size > 1
|
|
238
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
|
|
239
|
+
Bullet::Detector::CounterCache.add_possible_objects(records)
|
|
240
|
+
elsif records.size == 1
|
|
241
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
|
|
242
|
+
Bullet::Detector::CounterCache.add_impossible_object(records.first)
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
records
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def empty?
|
|
250
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
|
251
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
252
|
+
end
|
|
253
|
+
super
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def include?(object)
|
|
257
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations) if Bullet.start?
|
|
258
|
+
super
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
::ActiveRecord::Associations::SingularAssociation.prepend(
|
|
264
|
+
Module.new do
|
|
265
|
+
# call has_one and belongs_to associations
|
|
266
|
+
def reader
|
|
267
|
+
result = super
|
|
268
|
+
|
|
269
|
+
if Bullet.start?
|
|
270
|
+
if owner.class.name !~ /^HABTM_/
|
|
271
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
|
272
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
|
273
|
+
association = owner.association(reflection.through_reflection.name)
|
|
274
|
+
Array.wrap(association.target).each do |through_record|
|
|
275
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
if reflection.through_reflection != through_reflection
|
|
279
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
283
|
+
|
|
284
|
+
if Bullet::Detector::NPlusOneQuery.impossible?(owner)
|
|
285
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
|
|
286
|
+
else
|
|
287
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
result
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(
|
|
297
|
+
Module.new do
|
|
298
|
+
def empty?
|
|
299
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
|
300
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name, caller_locations)
|
|
301
|
+
end
|
|
302
|
+
super
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def count_records
|
|
306
|
+
result = reflection.has_cached_counter?
|
|
307
|
+
if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
|
308
|
+
Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
|
|
309
|
+
end
|
|
310
|
+
super
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
::ActiveRecord::Associations::CollectionProxy.prepend(
|
|
316
|
+
Module.new do
|
|
317
|
+
def count(column_name = nil)
|
|
318
|
+
if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
|
319
|
+
Bullet::Detector::CounterCache.add_counter_cache(
|
|
320
|
+
proxy_association.owner,
|
|
321
|
+
proxy_association.reflection.name
|
|
322
|
+
)
|
|
323
|
+
Bullet::Detector::NPlusOneQuery.call_association(
|
|
324
|
+
proxy_association.owner,
|
|
325
|
+
proxy_association.reflection.name,
|
|
326
|
+
caller_locations
|
|
327
|
+
)
|
|
328
|
+
end
|
|
329
|
+
super(column_name)
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
)
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
data/lib/bullet/dependency.rb
CHANGED
|
@@ -25,6 +25,8 @@ module Bullet
|
|
|
25
25
|
'active_record80'
|
|
26
26
|
elsif active_record81?
|
|
27
27
|
'active_record81'
|
|
28
|
+
elsif active_record82?
|
|
29
|
+
'active_record82'
|
|
28
30
|
else
|
|
29
31
|
raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
|
|
30
32
|
end
|
|
@@ -84,6 +86,10 @@ module Bullet
|
|
|
84
86
|
active_record8? && ::ActiveRecord::VERSION::MINOR == 1
|
|
85
87
|
end
|
|
86
88
|
|
|
89
|
+
def active_record82?
|
|
90
|
+
active_record8? && ::ActiveRecord::VERSION::MINOR == 2
|
|
91
|
+
end
|
|
92
|
+
|
|
87
93
|
def mongoid4x?
|
|
88
94
|
mongoid? && ::Mongoid::VERSION =~ /\A4/
|
|
89
95
|
end
|
|
@@ -36,7 +36,7 @@ module Bullet
|
|
|
36
36
|
# that the objects may cause N+1 query.
|
|
37
37
|
# e.g. { Post => ["Post:1", "Post:2"] }
|
|
38
38
|
def possible_objects
|
|
39
|
-
|
|
39
|
+
Bullet.state[:bullet_possible_objects]
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
# impossible_objects keep the class to objects relationships
|
|
@@ -45,7 +45,7 @@ module Bullet
|
|
|
45
45
|
# if find collection returns only one object, then the object is impossible object,
|
|
46
46
|
# impossible_objects are used to avoid treating 1+1 query to N+1 query.
|
|
47
47
|
def impossible_objects
|
|
48
|
-
|
|
48
|
+
Bullet.state[:bullet_impossible_objects]
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
private
|
|
@@ -56,7 +56,7 @@ module Bullet
|
|
|
56
56
|
# the object_associations keep all associations that may be or may no be
|
|
57
57
|
# unpreload associations or unused preload associations.
|
|
58
58
|
def object_associations
|
|
59
|
-
|
|
59
|
+
Bullet.state[:bullet_object_associations]
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
# call_object_associations keep the object relationships
|
|
@@ -64,27 +64,27 @@ module Bullet
|
|
|
64
64
|
# e.g. { "Post:1" => [:comments] }
|
|
65
65
|
# they are used to detect unused preload associations.
|
|
66
66
|
def call_object_associations
|
|
67
|
-
|
|
67
|
+
Bullet.state[:bullet_call_object_associations]
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
# inversed_objects keeps object relationships
|
|
71
71
|
# that association is inversed.
|
|
72
72
|
# e.g. { "Comment:1" => ["post"] }
|
|
73
73
|
def inversed_objects
|
|
74
|
-
|
|
74
|
+
Bullet.state[:bullet_inversed_objects]
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
# eager_loadings keep the object relationships
|
|
78
78
|
# that the associations are preloaded by find :include.
|
|
79
79
|
# e.g. { ["Post:1", "Post:2"] => [:comments, :user] }
|
|
80
80
|
def eager_loadings
|
|
81
|
-
|
|
81
|
+
Bullet.state[:bullet_eager_loadings]
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
# call_stacks keeps stacktraces where querie-objects were called from.
|
|
85
85
|
# e.g. { 'Object:111' => [SomeProject/app/controllers/...] }
|
|
86
86
|
def call_stacks
|
|
87
|
-
|
|
87
|
+
Bullet.state[:bullet_call_stacks]
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
90
|
end
|
|
@@ -46,11 +46,11 @@ module Bullet
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def possible_objects
|
|
49
|
-
|
|
49
|
+
Bullet.state[:bullet_counter_possible_objects]
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def impossible_objects
|
|
53
|
-
|
|
53
|
+
Bullet.state[:bullet_counter_impossible_objects]
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
private
|
data/lib/bullet/rack.rb
CHANGED
data/lib/bullet/version.rb
CHANGED
data/lib/bullet.rb
CHANGED
|
@@ -39,10 +39,10 @@ module Bullet
|
|
|
39
39
|
:counter_cache_enable,
|
|
40
40
|
:stacktrace_includes,
|
|
41
41
|
:stacktrace_excludes,
|
|
42
|
-
:skip_html_injection
|
|
42
|
+
:skip_html_injection,
|
|
43
|
+
:footer_position
|
|
43
44
|
attr_reader :safelist
|
|
44
45
|
attr_accessor :add_footer,
|
|
45
|
-
:footer_position,
|
|
46
46
|
:orm_patches_applied,
|
|
47
47
|
:skip_http_headers,
|
|
48
48
|
:always_append_html_body,
|
|
@@ -149,56 +149,71 @@ module Bullet
|
|
|
149
149
|
puts "[Bullet][#{title}] #{message}" if ENV['BULLET_DEBUG'] == 'true'
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
+
# Fiber storage reaches child fibers; start_request gives each request its own, and the owner check keeps it off new threads.
|
|
153
|
+
def state
|
|
154
|
+
unless Fiber.respond_to?(:[])
|
|
155
|
+
return Thread.current.thread_variable_get(:bullet_state) || Thread.current.thread_variable_set(:bullet_state, {})
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
current = Fiber[:bullet_state]
|
|
159
|
+
return current if current && current[:owner].equal?(Thread.current)
|
|
160
|
+
|
|
161
|
+
Fiber[:bullet_state] = { owner: Thread.current }
|
|
162
|
+
end
|
|
163
|
+
|
|
152
164
|
def start_request
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
if Fiber.respond_to?(:[])
|
|
166
|
+
Fiber[:bullet_state] = state.slice(:owner)
|
|
167
|
+
end
|
|
168
|
+
Bullet.state[:bullet_start] = true
|
|
169
|
+
Bullet.state[:bullet_notification_collector] = Bullet::NotificationCollector.new
|
|
170
|
+
|
|
171
|
+
Bullet.state[:bullet_object_associations] = Bullet::Registry::Base.new
|
|
172
|
+
Bullet.state[:bullet_call_object_associations] = Bullet::Registry::Base.new
|
|
173
|
+
Bullet.state[:bullet_possible_objects] = Bullet::Registry::Object.new
|
|
174
|
+
Bullet.state[:bullet_impossible_objects] = Bullet::Registry::Object.new
|
|
175
|
+
Bullet.state[:bullet_inversed_objects] = Bullet::Registry::Base.new
|
|
176
|
+
Bullet.state[:bullet_eager_loadings] = Bullet::Registry::Association.new
|
|
177
|
+
Bullet.state[:bullet_call_stacks] = Bullet::Registry::CallStack.new
|
|
178
|
+
|
|
179
|
+
unless Bullet.state[:bullet_counter_possible_objects]
|
|
180
|
+
Bullet.state[:bullet_counter_possible_objects] = Bullet::Registry::Object.new
|
|
166
181
|
end
|
|
167
182
|
|
|
168
|
-
unless
|
|
169
|
-
|
|
183
|
+
unless Bullet.state[:bullet_counter_impossible_objects]
|
|
184
|
+
Bullet.state[:bullet_counter_impossible_objects] = Bullet::Registry::Object.new
|
|
170
185
|
end
|
|
171
186
|
end
|
|
172
187
|
|
|
173
188
|
def end_request
|
|
174
|
-
|
|
175
|
-
|
|
189
|
+
Bullet.state[:bullet_start] = nil
|
|
190
|
+
Bullet.state[:bullet_notification_collector] = nil
|
|
176
191
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
192
|
+
Bullet.state[:bullet_object_associations] = nil
|
|
193
|
+
Bullet.state[:bullet_call_object_associations] = nil
|
|
194
|
+
Bullet.state[:bullet_possible_objects] = nil
|
|
195
|
+
Bullet.state[:bullet_impossible_objects] = nil
|
|
196
|
+
Bullet.state[:bullet_inversed_objects] = nil
|
|
197
|
+
Bullet.state[:bullet_eager_loadings] = nil
|
|
183
198
|
|
|
184
|
-
|
|
185
|
-
|
|
199
|
+
Bullet.state[:bullet_counter_possible_objects] = nil
|
|
200
|
+
Bullet.state[:bullet_counter_impossible_objects] = nil
|
|
186
201
|
end
|
|
187
202
|
|
|
188
203
|
def start?
|
|
189
|
-
enable? &&
|
|
204
|
+
enable? && Bullet.state[:bullet_start]
|
|
190
205
|
end
|
|
191
206
|
|
|
192
207
|
def pause
|
|
193
|
-
|
|
208
|
+
Bullet.state[:bullet_start] = false
|
|
194
209
|
end
|
|
195
210
|
|
|
196
211
|
def resume
|
|
197
|
-
|
|
212
|
+
Bullet.state[:bullet_start] = true
|
|
198
213
|
end
|
|
199
214
|
|
|
200
215
|
def paused?
|
|
201
|
-
enable? && !
|
|
216
|
+
enable? && !Bullet.state[:bullet_start]
|
|
202
217
|
end
|
|
203
218
|
|
|
204
219
|
def skip
|
|
@@ -210,7 +225,7 @@ module Bullet
|
|
|
210
225
|
end
|
|
211
226
|
|
|
212
227
|
def notification_collector
|
|
213
|
-
|
|
228
|
+
Bullet.state[:bullet_notification_collector]
|
|
214
229
|
end
|
|
215
230
|
|
|
216
231
|
def notification?
|
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.
|
|
4
|
+
version: 8.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Richard Huang
|
|
@@ -82,6 +82,7 @@ files:
|
|
|
82
82
|
- lib/bullet/active_record72.rb
|
|
83
83
|
- lib/bullet/active_record80.rb
|
|
84
84
|
- lib/bullet/active_record81.rb
|
|
85
|
+
- lib/bullet/active_record82.rb
|
|
85
86
|
- lib/bullet/bullet_xhr.js
|
|
86
87
|
- lib/bullet/dependency.rb
|
|
87
88
|
- lib/bullet/detector.rb
|
|
@@ -134,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
134
135
|
- !ruby/object:Gem::Version
|
|
135
136
|
version: 1.3.6
|
|
136
137
|
requirements: []
|
|
137
|
-
rubygems_version: 4.0.
|
|
138
|
+
rubygems_version: 4.0.20
|
|
138
139
|
specification_version: 4
|
|
139
140
|
summary: help to kill N+1 queries and unused eager loading.
|
|
140
141
|
test_files: []
|