bullet 7.2.0 → 8.0.8
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 +48 -1
- data/MIT-LICENSE +1 -1
- data/README.md +34 -7
- data/lib/bullet/active_record4.rb +4 -1
- data/lib/bullet/active_record41.rb +4 -1
- data/lib/bullet/active_record42.rb +4 -1
- data/lib/bullet/active_record5.rb +1 -0
- data/lib/bullet/active_record52.rb +1 -0
- data/lib/bullet/active_record60.rb +1 -0
- data/lib/bullet/active_record61.rb +1 -0
- data/lib/bullet/active_record70.rb +1 -0
- data/lib/bullet/active_record71.rb +1 -0
- data/lib/bullet/active_record72.rb +1 -0
- data/lib/bullet/active_record80.rb +319 -0
- data/lib/bullet/dependency.rb +16 -0
- data/lib/bullet/detector/association.rb +10 -8
- data/lib/bullet/detector/counter_cache.rb +4 -2
- data/lib/bullet/detector/n_plus_one_query.rb +21 -8
- data/lib/bullet/detector/unused_eager_loading.rb +3 -0
- data/lib/bullet/ext/object.rb +27 -20
- data/lib/bullet/ext/string.rb +10 -3
- data/lib/bullet/mongoid9x.rb +72 -0
- data/lib/bullet/rack.rb +55 -28
- data/lib/bullet/registry/base.rb +5 -1
- data/lib/bullet/registry/call_stack.rb +1 -1
- data/lib/bullet/registry/object.rb +3 -0
- data/lib/bullet/stack_trace_filter.rb +4 -4
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +36 -30
- metadata +6 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac2296e419c6f32f6ed2e2dbe92a344884d1197b8287bb6c67783a1587c31c72
|
4
|
+
data.tar.gz: 523f4b66265e7ca8b4d67b19ecd13a547f7ad55acbdbd8190ec1e48a1cb4993e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 463b978de4299a651821f4bf66ce219ba3def30f32d8fbb790086d10b869526578c2f5b441a1c0c5d368c03906e833a86b5ed88cda1a2f983e5769c04bf7efb2
|
7
|
+
data.tar.gz: 5ab230e714c07790210516fbb760007fbbb49875a4021950b8e5d2c8ab77e132240f632ee50a62ee25dc58f629663f6d9802bee626d870d456284e3d4130ed3e
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,55 @@
|
|
1
1
|
## Next Release
|
2
2
|
|
3
|
+
## 8.0.8 (05/30/2025)
|
4
|
+
|
5
|
+
* Add middleware after initializers
|
6
|
+
* Fix bullet composite primary key retrieval
|
7
|
+
|
8
|
+
## 8.0.7 (05/15/2025)
|
9
|
+
|
10
|
+
* Try to insert `Bullet::Rack` properly
|
11
|
+
|
12
|
+
## 8.0.6 (05/07/2025)
|
13
|
+
|
14
|
+
* Add CSP nonce for footer styles as well
|
15
|
+
* Add support for OpenTelemetry reporting
|
16
|
+
|
17
|
+
## 8.0.5 (04/21/2025)
|
18
|
+
|
19
|
+
* Properly insert ContentSecurityPolicy middleware
|
20
|
+
* Properly parse query string
|
21
|
+
|
22
|
+
## 8.0.4 (04/18/2025)
|
23
|
+
|
24
|
+
* Insert bullet middleware before `ContentSecurityPolicy`
|
25
|
+
* Support url query `skip_html_injection=true`
|
26
|
+
* Mark object as impossible after updating inversed
|
27
|
+
|
28
|
+
## 8.0.3 (04/04/2025)
|
29
|
+
|
30
|
+
* Update non persisted `inversed_objects`
|
31
|
+
|
32
|
+
## 8.0.2 (04/02/2025)
|
33
|
+
|
34
|
+
* Do not cache `bullet_key` if object is not persisted
|
35
|
+
|
36
|
+
## 8.0.1 (02/10/2025)
|
37
|
+
|
38
|
+
* Update benchmark to use sqlite
|
39
|
+
* Reduce mem allocations
|
40
|
+
* Require active_support's inflections module before requiring the delegation module
|
41
|
+
|
42
|
+
## 8.0.0 (11/10/2024)
|
43
|
+
|
44
|
+
* Support Rails 8
|
45
|
+
* Drop Rails 4.0 and 4.1 support
|
46
|
+
* Require Ruby at least 2.7.0
|
47
|
+
* Store global objects into thread-local variables
|
48
|
+
* Avoid globally polluting `::String` and `::Object` classes
|
49
|
+
|
3
50
|
## 7.2.0 (07/12/2024)
|
4
51
|
|
5
|
-
* Support
|
52
|
+
* Support Rails 7.2
|
6
53
|
* Fix count method signature for active_record5 and active_record60
|
7
54
|
|
8
55
|
## 7.1.6 (01/16/2024)
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|

|
4
4
|
[](http://badge.fury.io/rb/bullet)
|
5
5
|
[](https://awesomecode.io/repos/flyerhzm/bullet)
|
6
|
-
[](https://coderwall.com/flyerhzm)
|
7
7
|
|
8
8
|
The Bullet gem is designed to help you increase your application's performance by reducing the number of queries it makes. It will watch your queries while you develop your application and notify you when you should add eager loading (N+1 queries), when you're using eager loading that isn't necessary and when you should use counter cache.
|
9
9
|
|
@@ -20,7 +20,7 @@ If you use activerecord 3.x, please use bullet < 5.5.0
|
|
20
20
|
* [http://railscasts.com/episodes/372-bullet](http://railscasts.com/episodes/372-bullet)
|
21
21
|
* [http://ruby5.envylabs.com/episodes/9-episode-8-september-8-2009](http://ruby5.envylabs.com/episodes/9-episode-8-september-8-2009)
|
22
22
|
* [http://railslab.newrelic.com/2009/10/23/episode-19-on-the-edge-part-1](http://railslab.newrelic.com/2009/10/23/episode-19-on-the-edge-part-1)
|
23
|
-
* [
|
23
|
+
* [https://rubyonrails.org/2009/10/22/community-highlights](https://rubyonrails.org/2009/10/22/community-highlights)
|
24
24
|
|
25
25
|
## Install
|
26
26
|
|
@@ -74,6 +74,7 @@ config.after_initialize do
|
|
74
74
|
Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
|
75
75
|
Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware', ['my_file.rb', 'my_method'], ['my_file.rb', 16..20] ]
|
76
76
|
Bullet.slack = { webhook_url: 'http://some.slack.url', channel: '#default', username: 'notifier' }
|
77
|
+
Bullet.opentelemetry = true
|
77
78
|
end
|
78
79
|
```
|
79
80
|
|
@@ -100,6 +101,7 @@ The code above will enable all of the Bullet notification systems:
|
|
100
101
|
Each item can be a string (match substring), a regex, or an array where the first item is a path to match, and the second
|
101
102
|
item is a line number, a Range of line numbers, or a (bare) method name, to exclude only particular lines in a file.
|
102
103
|
* `Bullet.slack`: add notifications to slack
|
104
|
+
* `Bullet.opentelemetry`: add notifications to OpenTelemetry
|
103
105
|
* `Bullet.raise`: raise errors, useful for making your specs fail unless they have optimized queries
|
104
106
|
* `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.
|
105
107
|
* `Bullet.skip_user_in_notification`: exclude the OS user (`whoami`) from notifications.
|
@@ -121,8 +123,6 @@ Bullet.unused_eager_loading_enable = false
|
|
121
123
|
Bullet.counter_cache_enable = false
|
122
124
|
```
|
123
125
|
|
124
|
-
Note: When calling `Bullet.enable`, all other detectors are reset to their defaults (`true`) and need reconfiguring.
|
125
|
-
|
126
126
|
## Safe list
|
127
127
|
|
128
128
|
Sometimes Bullet may notify you of query problems you don't care to fix, or
|
@@ -194,6 +194,11 @@ see [https://github.com/flyerhzm/uniform_notifier](https://github.com/flyerhzm/u
|
|
194
194
|
|
195
195
|
Growl support is dropped from uniform_notifier 1.16.0, if you still want it, please use uniform_notifier 1.15.0.
|
196
196
|
|
197
|
+
## URL query control
|
198
|
+
|
199
|
+
You can add the URL query parameter `skip_html_injection` to make the current HTML request behave as if `Bullet.skip_html_injection` is enabled,
|
200
|
+
e.g. `http://localhost:3000/posts?skip_html_injection=true`
|
201
|
+
|
197
202
|
## Important
|
198
203
|
|
199
204
|
If you find Bullet does not work for you, *please disable your browser's cache*.
|
@@ -240,7 +245,7 @@ If your application generates a Content-Security-Policy via a separate middlewar
|
|
240
245
|
|
241
246
|
### Run in tests
|
242
247
|
|
243
|
-
First you need to enable Bullet in test environment.
|
248
|
+
First you need to enable Bullet in the test environment.
|
244
249
|
|
245
250
|
```ruby
|
246
251
|
# config/environments/test.rb
|
@@ -251,11 +256,13 @@ config.after_initialize do
|
|
251
256
|
end
|
252
257
|
```
|
253
258
|
|
254
|
-
Then wrap each test in Bullet api.
|
259
|
+
Then wrap each test in the Bullet api.
|
260
|
+
|
261
|
+
With RSpec:
|
255
262
|
|
256
263
|
```ruby
|
257
264
|
# spec/rails_helper.rb
|
258
|
-
|
265
|
+
RSpec.configure do |config|
|
259
266
|
config.before(:each) do
|
260
267
|
Bullet.start_request
|
261
268
|
end
|
@@ -267,6 +274,26 @@ if Bullet.enable?
|
|
267
274
|
end
|
268
275
|
```
|
269
276
|
|
277
|
+
With Minitest:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
# test/test_helper.rb
|
281
|
+
module ActiveSupport
|
282
|
+
class TestCase
|
283
|
+
def before_setup
|
284
|
+
Bullet.start_request
|
285
|
+
super
|
286
|
+
end
|
287
|
+
|
288
|
+
def after_teardown
|
289
|
+
super
|
290
|
+
Bullet.perform_out_of_channel_notifications if Bullet.notification?
|
291
|
+
Bullet.end_request
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
```
|
296
|
+
|
270
297
|
## Debug Mode
|
271
298
|
|
272
299
|
Bullet outputs some details info, to enable debug mode, set
|
@@ -49,7 +49,10 @@ module Bullet
|
|
49
49
|
|
50
50
|
::ActiveRecord::Persistence.class_eval do
|
51
51
|
def _create_record_with_bullet(*args)
|
52
|
-
_create_record_without_bullet(*args).tap
|
52
|
+
_create_record_without_bullet(*args).tap do
|
53
|
+
Bullet::Detector::NPlusOneQuery.update_inversed_object(self)
|
54
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
55
|
+
end
|
53
56
|
end
|
54
57
|
alias_method_chain :_create_record, :bullet
|
55
58
|
end
|
@@ -52,7 +52,10 @@ module Bullet
|
|
52
52
|
|
53
53
|
::ActiveRecord::Persistence.class_eval do
|
54
54
|
def _create_record_with_bullet(*args)
|
55
|
-
_create_record_without_bullet(*args).tap
|
55
|
+
_create_record_without_bullet(*args).tap do
|
56
|
+
Bullet::Detector::NPlusOneQuery.update_inversed_object(self)
|
57
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
58
|
+
end
|
56
59
|
end
|
57
60
|
alias_method_chain :_create_record, :bullet
|
58
61
|
end
|
@@ -45,7 +45,10 @@ 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
|
48
|
+
_create_record_without_bullet(*args).tap do
|
49
|
+
Bullet::Detector::NPlusOneQuery.update_inversed_object(self)
|
50
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
51
|
+
end
|
49
52
|
end
|
50
53
|
alias_method_chain :_create_record, :bullet
|
51
54
|
end
|
@@ -0,0 +1,319 @@
|
|
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(sql, binds = [], preparable: nil, allow_retry: false, &block)
|
20
|
+
result = super
|
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
|
+
end
|
113
|
+
)
|
114
|
+
|
115
|
+
::ActiveRecord::Associations::JoinDependency.prepend(
|
116
|
+
Module.new do
|
117
|
+
def instantiate(result_set, strict_loading_value, &block)
|
118
|
+
@bullet_eager_loadings = {}
|
119
|
+
records = super
|
120
|
+
|
121
|
+
if Bullet.start?
|
122
|
+
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
123
|
+
objects = eager_loadings_hash.keys
|
124
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(
|
125
|
+
objects,
|
126
|
+
eager_loadings_hash[objects.first].to_a
|
127
|
+
)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
records
|
131
|
+
end
|
132
|
+
|
133
|
+
def construct(ar_parent, parent, row, seen, model_cache, strict_loading_value)
|
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
|
+
if node.reflection.through_reflection?
|
143
|
+
associations << node.reflection.through_reflection.name
|
144
|
+
end
|
145
|
+
associations.each do |association|
|
146
|
+
Bullet::Detector::Association.add_object_associations(ar_parent, association)
|
147
|
+
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, association)
|
148
|
+
@bullet_eager_loadings[ar_parent.class] ||= {}
|
149
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
|
150
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] << association
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
super
|
157
|
+
end
|
158
|
+
|
159
|
+
# call join associations
|
160
|
+
def construct_model(record, node, row, model_cache, id, strict_loading_value)
|
161
|
+
result = super
|
162
|
+
|
163
|
+
if Bullet.start?
|
164
|
+
associations = [node.reflection.name]
|
165
|
+
if node.reflection.through_reflection?
|
166
|
+
associations << node.reflection.through_reflection.name
|
167
|
+
end
|
168
|
+
associations.each do |association|
|
169
|
+
Bullet::Detector::Association.add_object_associations(record, association)
|
170
|
+
Bullet::Detector::NPlusOneQuery.call_association(record, association)
|
171
|
+
@bullet_eager_loadings[record.class] ||= {}
|
172
|
+
@bullet_eager_loadings[record.class][record] ||= Set.new
|
173
|
+
@bullet_eager_loadings[record.class][record] << association
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
result
|
178
|
+
end
|
179
|
+
end
|
180
|
+
)
|
181
|
+
|
182
|
+
::ActiveRecord::Associations::Association.prepend(
|
183
|
+
Module.new do
|
184
|
+
def inversed_from(record)
|
185
|
+
if Bullet.start?
|
186
|
+
Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
|
187
|
+
end
|
188
|
+
super
|
189
|
+
end
|
190
|
+
|
191
|
+
def inversed_from_queries(record)
|
192
|
+
if Bullet.start? && inversable?(record)
|
193
|
+
Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
|
194
|
+
end
|
195
|
+
super
|
196
|
+
end
|
197
|
+
end
|
198
|
+
)
|
199
|
+
|
200
|
+
::ActiveRecord::Associations::CollectionAssociation.prepend(
|
201
|
+
Module.new do
|
202
|
+
def load_target
|
203
|
+
records = super
|
204
|
+
|
205
|
+
if Bullet.start?
|
206
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
207
|
+
association = owner.association(reflection.through_reflection.name)
|
208
|
+
if association.loaded?
|
209
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
210
|
+
Array.wrap(association.target).each do |through_record|
|
211
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
212
|
+
end
|
213
|
+
|
214
|
+
if reflection.through_reflection != through_reflection
|
215
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
220
|
+
if records.first.class.name !~ /^HABTM_/
|
221
|
+
if records.size > 1
|
222
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
|
223
|
+
Bullet::Detector::CounterCache.add_possible_objects(records)
|
224
|
+
elsif records.size == 1
|
225
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
|
226
|
+
Bullet::Detector::CounterCache.add_impossible_object(records.first)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
records
|
231
|
+
end
|
232
|
+
|
233
|
+
def empty?
|
234
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
235
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
236
|
+
end
|
237
|
+
super
|
238
|
+
end
|
239
|
+
|
240
|
+
def include?(object)
|
241
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
|
242
|
+
super
|
243
|
+
end
|
244
|
+
end
|
245
|
+
)
|
246
|
+
|
247
|
+
::ActiveRecord::Associations::SingularAssociation.prepend(
|
248
|
+
Module.new do
|
249
|
+
# call has_one and belongs_to associations
|
250
|
+
def reader
|
251
|
+
result = super
|
252
|
+
|
253
|
+
if Bullet.start?
|
254
|
+
if owner.class.name !~ /^HABTM_/
|
255
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
256
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
257
|
+
association = owner.association(reflection.through_reflection.name)
|
258
|
+
Array.wrap(association.target).each do |through_record|
|
259
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
260
|
+
end
|
261
|
+
|
262
|
+
if reflection.through_reflection != through_reflection
|
263
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
267
|
+
|
268
|
+
if Bullet::Detector::NPlusOneQuery.impossible?(owner)
|
269
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
|
270
|
+
else
|
271
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
result
|
276
|
+
end
|
277
|
+
end
|
278
|
+
)
|
279
|
+
|
280
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(
|
281
|
+
Module.new do
|
282
|
+
def empty?
|
283
|
+
result = super
|
284
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
285
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
286
|
+
end
|
287
|
+
result
|
288
|
+
end
|
289
|
+
|
290
|
+
def count_records
|
291
|
+
result = reflection.has_cached_counter?
|
292
|
+
if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
293
|
+
Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
|
294
|
+
end
|
295
|
+
super
|
296
|
+
end
|
297
|
+
end
|
298
|
+
)
|
299
|
+
|
300
|
+
::ActiveRecord::Associations::CollectionProxy.prepend(
|
301
|
+
Module.new do
|
302
|
+
def count(column_name = nil)
|
303
|
+
if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
304
|
+
Bullet::Detector::CounterCache.add_counter_cache(
|
305
|
+
proxy_association.owner,
|
306
|
+
proxy_association.reflection.name
|
307
|
+
)
|
308
|
+
Bullet::Detector::NPlusOneQuery.call_association(
|
309
|
+
proxy_association.owner,
|
310
|
+
proxy_association.reflection.name
|
311
|
+
)
|
312
|
+
end
|
313
|
+
super(column_name)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
data/lib/bullet/dependency.rb
CHANGED
@@ -35,6 +35,8 @@ module Bullet
|
|
35
35
|
'active_record71'
|
36
36
|
elsif active_record72?
|
37
37
|
'active_record72'
|
38
|
+
elsif active_record80?
|
39
|
+
'active_record80'
|
38
40
|
else
|
39
41
|
raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
|
40
42
|
end
|
@@ -54,6 +56,8 @@ module Bullet
|
|
54
56
|
'mongoid7x'
|
55
57
|
elsif mongoid8x?
|
56
58
|
'mongoid8x'
|
59
|
+
elsif mongoid9x?
|
60
|
+
'mongoid9x'
|
57
61
|
else
|
58
62
|
raise "Bullet does not support mongoid #{::Mongoid::VERSION} yet"
|
59
63
|
end
|
@@ -76,6 +80,10 @@ module Bullet
|
|
76
80
|
active_record? && ::ActiveRecord::VERSION::MAJOR == 7
|
77
81
|
end
|
78
82
|
|
83
|
+
def active_record8?
|
84
|
+
active_record? && ::ActiveRecord::VERSION::MAJOR == 8
|
85
|
+
end
|
86
|
+
|
79
87
|
def active_record40?
|
80
88
|
active_record4? && ::ActiveRecord::VERSION::MINOR == 0
|
81
89
|
end
|
@@ -120,6 +128,10 @@ module Bullet
|
|
120
128
|
active_record7? && ::ActiveRecord::VERSION::MINOR == 2
|
121
129
|
end
|
122
130
|
|
131
|
+
def active_record80?
|
132
|
+
active_record8? && ::ActiveRecord::VERSION::MINOR == 0
|
133
|
+
end
|
134
|
+
|
123
135
|
def mongoid4x?
|
124
136
|
mongoid? && ::Mongoid::VERSION =~ /\A4/
|
125
137
|
end
|
@@ -139,5 +151,9 @@ module Bullet
|
|
139
151
|
def mongoid8x?
|
140
152
|
mongoid? && ::Mongoid::VERSION =~ /\A8/
|
141
153
|
end
|
154
|
+
|
155
|
+
def mongoid9x?
|
156
|
+
mongoid? && ::Mongoid::VERSION =~ /\A9/
|
157
|
+
end
|
142
158
|
end
|
143
159
|
end
|