bullet 8.1.3 → 8.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +19 -6
- data/lib/bullet/active_record70.rb +14 -0
- data/lib/bullet/active_record71.rb +14 -0
- data/lib/bullet/active_record72.rb +14 -0
- data/lib/bullet/active_record80.rb +14 -0
- data/lib/bullet/active_record81.rb +14 -0
- data/lib/bullet/{active_record60.rb → active_record82.rb} +74 -49
- data/lib/bullet/dependency.rb +10 -58
- data/lib/bullet/detector/association.rb +2 -2
- data/lib/bullet/detector/n_plus_one_query.rb +1 -1
- data/lib/bullet/rack.rb +35 -2
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +25 -0
- metadata +30 -8
- data/lib/bullet/active_record4.rb +0 -197
- data/lib/bullet/active_record41.rb +0 -191
- data/lib/bullet/active_record42.rb +0 -262
- data/lib/bullet/active_record5.rb +0 -294
- data/lib/bullet/active_record52.rb +0 -278
- data/lib/bullet/active_record61.rb +0 -310
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce3dc25a18b75ec4068eae5386c39a96ac90775b2b410efd64f9993790205b83
|
|
4
|
+
data.tar.gz: a777865c06b2b8102a834db3d8a943bd41b2aadf92a91ecbc23f466dcc2bdea6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 643e6e91d5cb5a3d1de379b738451e82a3e9e7691f2a78a0d7721bac47deaff49181ac93f54cc8fd3390c34732d2bfdea0f4f0701bfb509e0fa9af789f41c519
|
|
7
|
+
data.tar.gz: 70982dc3a2e6cfe721ee126dd138f0c3ff9b0401d5376db35bc88f7245fcb6364f00ebae0e11401658a36e28964d7806d90f6eff15dc498b7e4aecdb32969884
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
## 8.3.0 (10/10/2026)
|
|
4
|
+
|
|
5
|
+
* Add support for ActiveRecord 8.2
|
|
6
|
+
|
|
7
|
+
## 8.2.0 (08/29/2026)
|
|
8
|
+
|
|
9
|
+
* Add thread-safe `Bullet.pause`, `Bullet.resume`, `Bullet.paused?`, and `Bullet.skip` APIs
|
|
10
|
+
* Add configurable footer positioning
|
|
11
|
+
* Fix unused eager loading false positives when N+1 detection is disabled
|
|
12
|
+
* Fix unused eager loading false positives for conditional `has_many :through` associations
|
|
13
|
+
* Fix Ruby 4.0 compatibility issues
|
|
14
|
+
* Drop support for ActiveRecord versions older than 7 and Mongoid versions older than 8
|
|
15
|
+
|
|
3
16
|
## 8.1.3 (06/02/2026)
|
|
4
17
|
|
|
5
18
|
* Handle inversed polymorphic belongs_to false positives
|
data/README.md
CHANGED
|
@@ -69,6 +69,7 @@ config.after_initialize do
|
|
|
69
69
|
Bullet.airbrake = true
|
|
70
70
|
Bullet.rollbar = true
|
|
71
71
|
Bullet.add_footer = true
|
|
72
|
+
Bullet.footer_position = 'bottom_left' # or 'bottom_right', 'top_left', 'top_right'
|
|
72
73
|
Bullet.skip_html_injection = false
|
|
73
74
|
Bullet.skip_http_headers = false
|
|
74
75
|
Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
|
|
@@ -97,6 +98,7 @@ The code above will enable all of the Bullet notification systems:
|
|
|
97
98
|
* `Bullet.airbrake`: add notifications to airbrake
|
|
98
99
|
* `Bullet.rollbar`: add notifications to rollbar
|
|
99
100
|
* `Bullet.add_footer`: adds the details in the bottom left corner of the page. Double click the footer or use close button to hide footer.
|
|
101
|
+
* `Bullet.footer_position`: position of the footer on the page. Valid values are 'bottom_left' (default), 'bottom_right', 'top_left', or 'top_right'. This is useful when the default position clashes with browser UI elements like Chrome's URL preview.
|
|
100
102
|
* `Bullet.skip_html_injection`: prevents Bullet from injecting code into the returned HTML. This must be false for receiving alerts, showing the footer or console logging.
|
|
101
103
|
* `Bullet.skip_http_headers`: don't add headers to API requests, and remove the javascript that relies on them. Note that this prevents bullet from logging warnings to the browser console or updating the footer.
|
|
102
104
|
* `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
|
|
@@ -137,23 +139,34 @@ Bullet.add_safelist :type => :unused_eager_loading, :class_name => "Post", :asso
|
|
|
137
139
|
Bullet.add_safelist :type => :counter_cache, :class_name => "Country", :association => :cities
|
|
138
140
|
```
|
|
139
141
|
|
|
142
|
+
## Skip Bullet in specific actions
|
|
143
|
+
|
|
140
144
|
If you want to skip bullet in some specific controller actions, you can
|
|
141
|
-
|
|
145
|
+
use `Bullet.skip`, which is thread-safe and works correctly in multi-threaded
|
|
146
|
+
environments like Puma.
|
|
142
147
|
|
|
143
148
|
```ruby
|
|
144
149
|
class ApplicationController < ActionController::Base
|
|
145
150
|
around_action :skip_bullet, if: -> { defined?(Bullet) }
|
|
146
151
|
|
|
147
152
|
def skip_bullet
|
|
148
|
-
|
|
149
|
-
Bullet.enable = false
|
|
150
|
-
yield
|
|
151
|
-
ensure
|
|
152
|
-
Bullet.enable = previous_value
|
|
153
|
+
Bullet.skip { yield }
|
|
153
154
|
end
|
|
154
155
|
end
|
|
155
156
|
```
|
|
156
157
|
|
|
158
|
+
For more granular control, you can also use `Bullet.pause` and `Bullet.resume`:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
Bullet.pause # Temporarily disable detection for current thread
|
|
162
|
+
Bullet.resume # Re-enable detection for current thread
|
|
163
|
+
Bullet.paused? # Check if detection is paused for current thread
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Note**: Do not toggle `Bullet.enable` at runtime, as it modifies a global
|
|
167
|
+
flag that is not thread-safe. Use `Bullet.skip`, `Bullet.pause`, or
|
|
168
|
+
`Bullet.start_request`/`Bullet.end_request` instead.
|
|
169
|
+
|
|
157
170
|
## Log
|
|
158
171
|
|
|
159
172
|
The Bullet log `log/bullet.log` will look something like this:
|
|
@@ -109,6 +109,20 @@ module Bullet
|
|
|
109
109
|
super
|
|
110
110
|
end
|
|
111
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
|
|
112
126
|
end
|
|
113
127
|
)
|
|
114
128
|
|
|
@@ -109,6 +109,20 @@ module Bullet
|
|
|
109
109
|
super
|
|
110
110
|
end
|
|
111
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
|
|
112
126
|
end
|
|
113
127
|
)
|
|
114
128
|
|
|
@@ -109,6 +109,20 @@ module Bullet
|
|
|
109
109
|
super
|
|
110
110
|
end
|
|
111
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
|
|
112
126
|
end
|
|
113
127
|
)
|
|
114
128
|
|
|
@@ -109,6 +109,20 @@ module Bullet
|
|
|
109
109
|
super
|
|
110
110
|
end
|
|
111
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
|
|
112
126
|
end
|
|
113
127
|
)
|
|
114
128
|
|
|
@@ -109,6 +109,20 @@ module Bullet
|
|
|
109
109
|
super
|
|
110
110
|
end
|
|
111
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
|
|
112
126
|
end
|
|
113
127
|
)
|
|
114
128
|
|
|
@@ -16,8 +16,8 @@ module Bullet
|
|
|
16
16
|
require 'active_record'
|
|
17
17
|
::ActiveRecord::Base.extend(
|
|
18
18
|
Module.new do
|
|
19
|
-
def find_by_sql(
|
|
20
|
-
result = super
|
|
19
|
+
def find_by_sql(*args, **kwargs, &block)
|
|
20
|
+
result = super(*args, **kwargs, &block)
|
|
21
21
|
if Bullet.start?
|
|
22
22
|
if result.is_a? Array
|
|
23
23
|
if result.size > 1
|
|
@@ -61,25 +61,32 @@ module Bullet
|
|
|
61
61
|
end
|
|
62
62
|
)
|
|
63
63
|
|
|
64
|
-
::ActiveRecord::Associations::Preloader.prepend(
|
|
64
|
+
::ActiveRecord::Associations::Preloader::Batch.prepend(
|
|
65
65
|
Module.new do
|
|
66
|
-
def
|
|
66
|
+
def call
|
|
67
67
|
if Bullet.start?
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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)
|
|
72
73
|
end
|
|
73
74
|
end
|
|
74
75
|
super
|
|
75
76
|
end
|
|
77
|
+
end
|
|
78
|
+
)
|
|
76
79
|
|
|
77
|
-
|
|
80
|
+
::ActiveRecord::Associations::Preloader::Branch.prepend(
|
|
81
|
+
Module.new do
|
|
82
|
+
def preloaders_for_reflection(reflection, reflection_records)
|
|
78
83
|
if Bullet.start?
|
|
79
|
-
|
|
80
|
-
if
|
|
81
|
-
|
|
82
|
-
|
|
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)
|
|
83
90
|
end
|
|
84
91
|
end
|
|
85
92
|
super
|
|
@@ -89,25 +96,41 @@ module Bullet
|
|
|
89
96
|
|
|
90
97
|
::ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(
|
|
91
98
|
Module.new do
|
|
92
|
-
def
|
|
93
|
-
if Bullet.start? && !defined?(@
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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|
|
|
97
105
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
|
98
106
|
end
|
|
99
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
|
|
100
124
|
end
|
|
101
|
-
super
|
|
102
125
|
end
|
|
103
126
|
end
|
|
104
127
|
)
|
|
105
128
|
|
|
106
129
|
::ActiveRecord::Associations::JoinDependency.prepend(
|
|
107
130
|
Module.new do
|
|
108
|
-
def instantiate(
|
|
131
|
+
def instantiate(*args, **kwargs, &block)
|
|
109
132
|
@bullet_eager_loadings = {}
|
|
110
|
-
records = super
|
|
133
|
+
records = super(*args, **kwargs, &block)
|
|
111
134
|
|
|
112
135
|
if Bullet.start?
|
|
113
136
|
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
|
@@ -121,7 +144,8 @@ module Bullet
|
|
|
121
144
|
records
|
|
122
145
|
end
|
|
123
146
|
|
|
124
|
-
def construct(
|
|
147
|
+
def construct(*args, **kwargs, &block)
|
|
148
|
+
ar_parent, parent, row = args
|
|
125
149
|
if Bullet.start?
|
|
126
150
|
unless ar_parent.nil?
|
|
127
151
|
parent.children.each do |node|
|
|
@@ -144,12 +168,13 @@ module Bullet
|
|
|
144
168
|
end
|
|
145
169
|
end
|
|
146
170
|
|
|
147
|
-
super
|
|
171
|
+
super(*args, **kwargs, &block)
|
|
148
172
|
end
|
|
149
173
|
|
|
150
174
|
# call join associations
|
|
151
|
-
def construct_model(
|
|
152
|
-
|
|
175
|
+
def construct_model(*args, **kwargs, &block)
|
|
176
|
+
record, node = args
|
|
177
|
+
result = super(*args, **kwargs, &block)
|
|
153
178
|
|
|
154
179
|
if Bullet.start?
|
|
155
180
|
associations = [node.reflection.name]
|
|
@@ -178,6 +203,13 @@ module Bullet
|
|
|
178
203
|
end
|
|
179
204
|
super
|
|
180
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
|
|
181
213
|
end
|
|
182
214
|
)
|
|
183
215
|
|
|
@@ -200,11 +232,7 @@ module Bullet
|
|
|
200
232
|
end
|
|
201
233
|
end
|
|
202
234
|
end
|
|
203
|
-
|
|
204
|
-
Bullet::Detector::Association.add_call_object_associations(owner, reflection.name)
|
|
205
|
-
else
|
|
206
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
207
|
-
end
|
|
235
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
208
236
|
if records.first.class.name !~ /^HABTM_/
|
|
209
237
|
if records.size > 1
|
|
210
238
|
Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
|
|
@@ -235,31 +263,28 @@ module Bullet
|
|
|
235
263
|
::ActiveRecord::Associations::SingularAssociation.prepend(
|
|
236
264
|
Module.new do
|
|
237
265
|
# call has_one and belongs_to associations
|
|
238
|
-
def
|
|
239
|
-
result = super
|
|
266
|
+
def reader
|
|
267
|
+
result = super
|
|
240
268
|
|
|
241
269
|
if Bullet.start?
|
|
242
270
|
if owner.class.name !~ /^HABTM_/
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
end
|
|
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
|
|
250
277
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
end
|
|
278
|
+
if reflection.through_reflection != through_reflection
|
|
279
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
|
254
280
|
end
|
|
255
281
|
end
|
|
256
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
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
|
|
263
288
|
end
|
|
264
289
|
end
|
|
265
290
|
end
|
data/lib/bullet/dependency.rb
CHANGED
|
@@ -13,22 +13,8 @@ module Bullet
|
|
|
13
13
|
def active_record_version
|
|
14
14
|
@active_record_version ||=
|
|
15
15
|
begin
|
|
16
|
-
if
|
|
17
|
-
|
|
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?
|
|
@@ -39,6 +25,8 @@ module Bullet
|
|
|
39
25
|
'active_record80'
|
|
40
26
|
elsif active_record81?
|
|
41
27
|
'active_record81'
|
|
28
|
+
elsif active_record82?
|
|
29
|
+
'active_record82'
|
|
42
30
|
else
|
|
43
31
|
raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
|
|
44
32
|
end
|
|
@@ -66,16 +54,8 @@ module Bullet
|
|
|
66
54
|
end
|
|
67
55
|
end
|
|
68
56
|
|
|
69
|
-
def
|
|
70
|
-
active_record? && ::ActiveRecord::VERSION::MAJOR
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def active_record5?
|
|
74
|
-
active_record? && ::ActiveRecord::VERSION::MAJOR == 5
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def active_record6?
|
|
78
|
-
active_record? && ::ActiveRecord::VERSION::MAJOR == 6
|
|
57
|
+
def active_record6_or_older?
|
|
58
|
+
active_record? && ::ActiveRecord::VERSION::MAJOR < 7
|
|
79
59
|
end
|
|
80
60
|
|
|
81
61
|
def active_record7?
|
|
@@ -86,38 +66,6 @@ module Bullet
|
|
|
86
66
|
active_record? && ::ActiveRecord::VERSION::MAJOR == 8
|
|
87
67
|
end
|
|
88
68
|
|
|
89
|
-
def active_record40?
|
|
90
|
-
active_record4? && ::ActiveRecord::VERSION::MINOR == 0
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def active_record41?
|
|
94
|
-
active_record4? && ::ActiveRecord::VERSION::MINOR == 1
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def active_record42?
|
|
98
|
-
active_record4? && ::ActiveRecord::VERSION::MINOR == 2
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def active_record50?
|
|
102
|
-
active_record5? && ::ActiveRecord::VERSION::MINOR == 0
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def active_record51?
|
|
106
|
-
active_record5? && ::ActiveRecord::VERSION::MINOR == 1
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def active_record52?
|
|
110
|
-
active_record5? && ::ActiveRecord::VERSION::MINOR == 2
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def active_record60?
|
|
114
|
-
active_record6? && ::ActiveRecord::VERSION::MINOR == 0
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def active_record61?
|
|
118
|
-
active_record6? && ::ActiveRecord::VERSION::MINOR == 1
|
|
119
|
-
end
|
|
120
|
-
|
|
121
69
|
def active_record70?
|
|
122
70
|
active_record7? && ::ActiveRecord::VERSION::MINOR == 0
|
|
123
71
|
end
|
|
@@ -138,6 +86,10 @@ module Bullet
|
|
|
138
86
|
active_record8? && ::ActiveRecord::VERSION::MINOR == 1
|
|
139
87
|
end
|
|
140
88
|
|
|
89
|
+
def active_record82?
|
|
90
|
+
active_record8? && ::ActiveRecord::VERSION::MINOR == 2
|
|
91
|
+
end
|
|
92
|
+
|
|
141
93
|
def mongoid4x?
|
|
142
94
|
mongoid? && ::Mongoid::VERSION =~ /\A4/
|
|
143
95
|
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
|
|
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
|
|
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(
|
|
@@ -15,7 +15,7 @@ module Bullet
|
|
|
15
15
|
# if it is, keeps this unpreload associations and caller.
|
|
16
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
20
|
|
|
21
21
|
# Record before early-returns so legitimate reads that bypass SQL
|
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;
|
|
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)
|
data/lib/bullet/version.rb
CHANGED
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,
|
|
@@ -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
|
|