bullet 7.0.7 → 7.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -1
  3. data/README.md +6 -3
  4. data/lib/bullet/active_record4.rb +10 -0
  5. data/lib/bullet/active_record41.rb +10 -0
  6. data/lib/bullet/active_record42.rb +10 -0
  7. data/lib/bullet/active_record5.rb +18 -0
  8. data/lib/bullet/active_record52.rb +18 -0
  9. data/lib/bullet/active_record60.rb +18 -0
  10. data/lib/bullet/active_record61.rb +18 -0
  11. data/lib/bullet/active_record70.rb +32 -8
  12. data/lib/bullet/active_record71.rb +308 -0
  13. data/lib/bullet/dependency.rb +12 -0
  14. data/lib/bullet/detector/n_plus_one_query.rb +2 -5
  15. data/lib/bullet/detector/unused_eager_loading.rb +5 -2
  16. data/lib/bullet/ext/object.rb +14 -3
  17. data/lib/bullet/mongoid8x.rb +59 -0
  18. data/lib/bullet/notification/base.rb +9 -8
  19. data/lib/bullet/notification/counter_cache.rb +1 -1
  20. data/lib/bullet/rack.rb +4 -2
  21. data/lib/bullet/registry/association.rb +2 -1
  22. data/lib/bullet/stack_trace_filter.rb +3 -2
  23. data/lib/bullet/version.rb +1 -1
  24. data/lib/bullet.rb +7 -2
  25. metadata +7 -155
  26. data/.github/workflows/main.yml +0 -82
  27. data/.gitignore +0 -15
  28. data/.rspec +0 -2
  29. data/Gemfile +0 -24
  30. data/Gemfile.mongoid +0 -12
  31. data/Gemfile.mongoid-4.0 +0 -15
  32. data/Gemfile.mongoid-5.0 +0 -15
  33. data/Gemfile.mongoid-6.0 +0 -15
  34. data/Gemfile.mongoid-7.0 +0 -15
  35. data/Gemfile.rails-4.0 +0 -16
  36. data/Gemfile.rails-4.1 +0 -16
  37. data/Gemfile.rails-4.2 +0 -16
  38. data/Gemfile.rails-5.0 +0 -15
  39. data/Gemfile.rails-5.1 +0 -15
  40. data/Gemfile.rails-5.2 +0 -15
  41. data/Gemfile.rails-6.0 +0 -15
  42. data/Gemfile.rails-6.1 +0 -15
  43. data/Gemfile.rails-7.0 +0 -10
  44. data/Guardfile +0 -8
  45. data/Hacking.md +0 -75
  46. data/Rakefile +0 -51
  47. data/bullet.gemspec +0 -33
  48. data/perf/benchmark.rb +0 -118
  49. data/rails/init.rb +0 -3
  50. data/spec/bullet/detector/association_spec.rb +0 -28
  51. data/spec/bullet/detector/base_spec.rb +0 -10
  52. data/spec/bullet/detector/counter_cache_spec.rb +0 -58
  53. data/spec/bullet/detector/n_plus_one_query_spec.rb +0 -150
  54. data/spec/bullet/detector/unused_eager_loading_spec.rb +0 -126
  55. data/spec/bullet/ext/object_spec.rb +0 -44
  56. data/spec/bullet/ext/string_spec.rb +0 -15
  57. data/spec/bullet/notification/base_spec.rb +0 -94
  58. data/spec/bullet/notification/counter_cache_spec.rb +0 -14
  59. data/spec/bullet/notification/n_plus_one_query_spec.rb +0 -29
  60. data/spec/bullet/notification/unused_eager_loading_spec.rb +0 -18
  61. data/spec/bullet/notification_collector_spec.rb +0 -34
  62. data/spec/bullet/rack_spec.rb +0 -296
  63. data/spec/bullet/registry/association_spec.rb +0 -28
  64. data/spec/bullet/registry/base_spec.rb +0 -46
  65. data/spec/bullet/registry/object_spec.rb +0 -26
  66. data/spec/bullet/stack_trace_filter_spec.rb +0 -26
  67. data/spec/bullet_spec.rb +0 -136
  68. data/spec/integration/active_record/association_spec.rb +0 -822
  69. data/spec/integration/counter_cache_spec.rb +0 -68
  70. data/spec/integration/mongoid/association_spec.rb +0 -246
  71. data/spec/models/address.rb +0 -5
  72. data/spec/models/attachment.rb +0 -5
  73. data/spec/models/author.rb +0 -5
  74. data/spec/models/base_user.rb +0 -7
  75. data/spec/models/category.rb +0 -12
  76. data/spec/models/city.rb +0 -5
  77. data/spec/models/client.rb +0 -8
  78. data/spec/models/comment.rb +0 -8
  79. data/spec/models/company.rb +0 -5
  80. data/spec/models/country.rb +0 -5
  81. data/spec/models/deal.rb +0 -5
  82. data/spec/models/document.rb +0 -7
  83. data/spec/models/entry.rb +0 -5
  84. data/spec/models/firm.rb +0 -7
  85. data/spec/models/folder.rb +0 -4
  86. data/spec/models/group.rb +0 -4
  87. data/spec/models/mongoid/address.rb +0 -9
  88. data/spec/models/mongoid/category.rb +0 -10
  89. data/spec/models/mongoid/comment.rb +0 -9
  90. data/spec/models/mongoid/company.rb +0 -9
  91. data/spec/models/mongoid/entry.rb +0 -9
  92. data/spec/models/mongoid/post.rb +0 -14
  93. data/spec/models/mongoid/user.rb +0 -7
  94. data/spec/models/newspaper.rb +0 -5
  95. data/spec/models/page.rb +0 -4
  96. data/spec/models/person.rb +0 -5
  97. data/spec/models/pet.rb +0 -5
  98. data/spec/models/post.rb +0 -34
  99. data/spec/models/relationship.rb +0 -6
  100. data/spec/models/reply.rb +0 -5
  101. data/spec/models/role.rb +0 -7
  102. data/spec/models/student.rb +0 -5
  103. data/spec/models/submission.rb +0 -7
  104. data/spec/models/teacher.rb +0 -5
  105. data/spec/models/user.rb +0 -8
  106. data/spec/models/writer.rb +0 -4
  107. data/spec/spec_helper.rb +0 -97
  108. data/spec/support/bullet_ext.rb +0 -56
  109. data/spec/support/mongo_seed.rb +0 -59
  110. data/spec/support/rack_double.rb +0 -49
  111. data/spec/support/sqlite_seed.rb +0 -284
  112. data/test.sh +0 -15
  113. 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: 68fdd5b4a91b98bb9fa4399088979b48a0e07432f268df9f0116b413433f8e89
4
+ data.tar.gz: d7832e74768e19a93355b7d67341cebedde9f14048b331b91564ed9b218f3a4d
5
5
  SHA512:
6
- metadata.gz: 87bf095754befedb8f1137ae039191807baa1f1bcadb09c923b4f1a6abd385e73e4143e50077358a8f7155e3bf367edb1b405e3b0b260c8de5dd572699b7bafc
7
- data.tar.gz: fd692ae67a1695ee4598b24d3cd030a7f091deb42f30df0f92085b3c54f765960c0b5eabaace7b306fadf8539b514fe77076cff825c27a292c5e36f56916646b
6
+ metadata.gz: 2a8ec0d54d2d0557793b1ad53b571ff5c04345d0e699d4052649b96f08ac911d5a200058fd9c13ee3ef342da65e14229f99e6cdc6fdab65668e468a062b1debe
7
+ data.tar.gz: 4c2606728e7e84f80dbbdfc66c34510825d4b365204718a1eaaf3a42247ff9c8708d5be321ae07aad95f0ddc3e57e97961327d58f1dced9912a7c26822584b54
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  ## Next Release
2
2
 
3
+ ## 7.1.3 (11/05/2023)
4
+
5
+ * Call NPlusOneQuery's call_association when calling count on collectino assocation
6
+
7
+ ## 7.1.2 (10/13/2023)
8
+
9
+ * Handle Rails 7.1 composite primary keys
10
+
11
+ ## 7.1.1 (10/07/2023)
12
+
13
+ * Add support for `Content-Security-Policy-Report-Only` nonces
14
+ * Fix count method signature
15
+
16
+ ## 7.1.0 (10/06/2023)
17
+
18
+ * Support rails 7.1
19
+ * Alias `Bullet.enable?` to `enabled?`, and `Bullet.enable=` to `enabled=`
20
+ * Added `always_append_html_body` option, so the html snippet is always included even if there are no notifications
21
+ * Added detection of n+1 count queries from `count` method
22
+ * Changed the counter cache notification title to recommend using `size`
23
+
3
24
  ## 7.0.7 (03/01/2023)
4
25
 
5
26
  * Check `Rails.application.config.content_security_policy` before insert `Bullet::Rack`
@@ -97,7 +118,7 @@
97
118
 
98
119
  * Fix through reflection for rails 5.x
99
120
  * Fix false positive in after_save/after_create callbacks
100
- * Don't triger a preload error on "manual" preloads
121
+ * Don't trigger a preload error on "manual" preloads
101
122
  * Avoid Bullet from making extra queries in mongoid6
102
123
  * Support option for #first and #last on mongoid6.x
103
124
  * 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
@@ -284,17 +287,17 @@ $ rails new test_bullet
284
287
  $ cd test_bullet
285
288
  $ rails g scaffold post name:string
286
289
  $ rails g scaffold comment name:string post_id:integer
287
- $ bundle exec rake db:migrate
290
+ $ bundle exec rails db:migrate
288
291
  ```
289
292
 
290
293
  2\. Change `app/models/post.rb` and `app/models/comment.rb`
291
294
 
292
295
  ```ruby
293
- class Post < ActiveRecord::Base
296
+ class Post < ApplicationRecord
294
297
  has_many :comments
295
298
  end
296
299
 
297
- class Comment < ActiveRecord::Base
300
+ class Comment < ApplicationRecord
298
301
  belongs_to :post
299
302
  end
300
303
  ```
@@ -176,6 +176,16 @@ module Bullet
176
176
  result
177
177
  end
178
178
  end
179
+
180
+ ::ActiveRecord::Associations::CollectionProxy.class_eval do
181
+ def count(column_name = nil, options = {})
182
+ if Bullet.start?
183
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
184
+ Bullet::Detector::NPlusOneQuery.call_association(proxy_association.owner, proxy_association.reflection.name)
185
+ end
186
+ super(column_name, options)
187
+ end
188
+ end
179
189
  end
180
190
  end
181
191
  end
@@ -168,6 +168,16 @@ module Bullet
168
168
  origin_count_records
169
169
  end
170
170
  end
171
+
172
+ ::ActiveRecord::Associations::CollectionProxy.class_eval do
173
+ def count(column_name = nil, options = {})
174
+ if Bullet.start?
175
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
176
+ Bullet::Detector::NPlusOneQuery.call_association(proxy_association.owner, proxy_association.reflection.name)
177
+ end
178
+ super(column_name, options)
179
+ end
180
+ end
171
181
  end
172
182
  end
173
183
  end
@@ -233,6 +233,16 @@ module Bullet
233
233
  origin_count_records
234
234
  end
235
235
  end
236
+
237
+ ::ActiveRecord::Associations::CollectionProxy.class_eval do
238
+ def count(column_name = nil, options = {})
239
+ if Bullet.start?
240
+ Bullet::Detector::CounterCache.add_counter_cache(proxy_association.owner, proxy_association.reflection.name)
241
+ Bullet::Detector::NPlusOneQuery.call_association(proxy_association.owner, proxy_association.reflection.name)
242
+ end
243
+ super(column_name, options)
244
+ end
245
+ end
236
246
  end
237
247
  end
238
248
  end
@@ -260,6 +260,24 @@ 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(
269
+ proxy_association.owner,
270
+ proxy_association.reflection.name
271
+ )
272
+ Bullet::Detector::NPlusOneQuery.call_association(
273
+ proxy_association.owner,
274
+ proxy_association.reflection.name
275
+ )
276
+ end
277
+ super
278
+ end
279
+ end
280
+ )
263
281
  end
264
282
  end
265
283
  end
@@ -242,6 +242,24 @@ module Bullet
242
242
  end
243
243
  end
244
244
  )
245
+
246
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
247
+ Module.new do
248
+ def count(column_name = nil)
249
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
250
+ Bullet::Detector::CounterCache.add_counter_cache(
251
+ proxy_association.owner,
252
+ proxy_association.reflection.name
253
+ )
254
+ Bullet::Detector::NPlusOneQuery.call_association(
255
+ proxy_association.owner,
256
+ proxy_association.reflection.name
257
+ )
258
+ end
259
+ super(column_name)
260
+ end
261
+ end
262
+ )
245
263
  end
246
264
  end
247
265
  end
@@ -269,6 +269,24 @@ 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(
278
+ proxy_association.owner,
279
+ proxy_association.reflection.name
280
+ )
281
+ Bullet::Detector::NPlusOneQuery.call_association(
282
+ proxy_association.owner,
283
+ proxy_association.reflection.name
284
+ )
285
+ end
286
+ super
287
+ end
288
+ end
289
+ )
272
290
  end
273
291
  end
274
292
  end
@@ -269,6 +269,24 @@ module Bullet
269
269
  end
270
270
  end
271
271
  )
272
+
273
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
274
+ Module.new do
275
+ def count(column_name = nil)
276
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
277
+ Bullet::Detector::CounterCache.add_counter_cache(
278
+ proxy_association.owner,
279
+ proxy_association.reflection.name
280
+ )
281
+ Bullet::Detector::NPlusOneQuery.call_association(
282
+ proxy_association.owner,
283
+ proxy_association.reflection.name
284
+ )
285
+ end
286
+ super(column_name)
287
+ end
288
+ end
289
+ )
272
290
  end
273
291
  end
274
292
  end
@@ -65,7 +65,9 @@ module Bullet
65
65
  def call
66
66
  if Bullet.start?
67
67
  @preloaders.each do |preloader|
68
- preloader.records.each { |record| Bullet::Detector::Association.add_object_associations(record, preloader.associations) }
68
+ preloader.records.each { |record|
69
+ Bullet::Detector::Association.add_object_associations(record, preloader.associations)
70
+ }
69
71
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(preloader.records, preloader.associations)
70
72
  end
71
73
  end
@@ -80,7 +82,9 @@ module Bullet
80
82
  if Bullet.start?
81
83
  reflection_records.compact!
82
84
  if reflection_records.first.class.name !~ /^HABTM_/
83
- reflection_records.each { |record| Bullet::Detector::Association.add_object_associations(record, reflection.name) }
85
+ reflection_records.each { |record|
86
+ Bullet::Detector::Association.add_object_associations(record, reflection.name)
87
+ }
84
88
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(reflection_records, reflection.name)
85
89
  end
86
90
  end
@@ -91,16 +95,18 @@ module Bullet
91
95
 
92
96
  ::ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(
93
97
  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|
98
+ def source_preloaders
99
+ if Bullet.start? && !defined?(@source_preloaders)
100
+ preloaders = super
101
+ preloaders.each do |preloader|
102
+ reflection_name = preloader.send(:reflection).name
103
+ preloader.send(:owners).each do |owner|
99
104
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
100
105
  end
101
106
  end
107
+ else
108
+ super
102
109
  end
103
- super
104
110
  end
105
111
  end
106
112
  )
@@ -279,6 +285,24 @@ module Bullet
279
285
  end
280
286
  end
281
287
  )
288
+
289
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
290
+ Module.new do
291
+ def count(column_name = nil)
292
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
293
+ Bullet::Detector::CounterCache.add_counter_cache(
294
+ proxy_association.owner,
295
+ proxy_association.reflection.name
296
+ )
297
+ Bullet::Detector::NPlusOneQuery.call_association(
298
+ proxy_association.owner,
299
+ proxy_association.reflection.name
300
+ )
301
+ end
302
+ super(column_name)
303
+ end
304
+ end
305
+ )
282
306
  end
283
307
  end
284
308
  end
@@ -0,0 +1,308 @@
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|
69
+ Bullet::Detector::Association.add_object_associations(record, preloader.associations)
70
+ }
71
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(preloader.records, preloader.associations)
72
+ end
73
+ end
74
+ super
75
+ end
76
+ end
77
+ )
78
+
79
+ ::ActiveRecord::Associations::Preloader::Branch.prepend(
80
+ Module.new do
81
+ def preloaders_for_reflection(reflection, reflection_records)
82
+ if Bullet.start?
83
+ reflection_records.compact!
84
+ if reflection_records.first.class.name !~ /^HABTM_/
85
+ reflection_records.each { |record|
86
+ Bullet::Detector::Association.add_object_associations(record, reflection.name)
87
+ }
88
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(reflection_records, reflection.name)
89
+ end
90
+ end
91
+ super
92
+ end
93
+ end
94
+ )
95
+
96
+ ::ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(
97
+ Module.new do
98
+ def source_preloaders
99
+ if Bullet.start? && !defined?(@source_preloaders)
100
+ preloaders = super
101
+ preloaders.each do |preloader|
102
+ reflection_name = preloader.send(:reflection).name
103
+ preloader.send(:owners).each do |owner|
104
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
105
+ end
106
+ end
107
+ else
108
+ super
109
+ end
110
+ end
111
+ end
112
+ )
113
+
114
+ ::ActiveRecord::Associations::JoinDependency.prepend(
115
+ Module.new do
116
+ def instantiate(result_set, strict_loading_value, &block)
117
+ @bullet_eager_loadings = {}
118
+ records = super
119
+
120
+ if Bullet.start?
121
+ @bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
122
+ objects = eager_loadings_hash.keys
123
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(
124
+ objects,
125
+ eager_loadings_hash[objects.first].to_a
126
+ )
127
+ end
128
+ end
129
+ records
130
+ end
131
+
132
+ def construct(ar_parent, parent, row, seen, model_cache, strict_loading_value)
133
+ if Bullet.start?
134
+ unless ar_parent.nil?
135
+ parent.children.each do |node|
136
+ key = aliases.column_alias(node, node.primary_key)
137
+ id = row[key]
138
+ next unless id.nil?
139
+
140
+ associations = node.reflection.name
141
+ Bullet::Detector::Association.add_object_associations(ar_parent, associations)
142
+ Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
143
+ @bullet_eager_loadings[ar_parent.class] ||= {}
144
+ @bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
145
+ @bullet_eager_loadings[ar_parent.class][ar_parent] << associations
146
+ end
147
+ end
148
+ end
149
+
150
+ super
151
+ end
152
+
153
+ # call join associations
154
+ def construct_model(record, node, row, model_cache, id, strict_loading_value)
155
+ result = super
156
+
157
+ if Bullet.start?
158
+ associations = node.reflection.name
159
+ Bullet::Detector::Association.add_object_associations(record, associations)
160
+ Bullet::Detector::NPlusOneQuery.call_association(record, associations)
161
+ @bullet_eager_loadings[record.class] ||= {}
162
+ @bullet_eager_loadings[record.class][record] ||= Set.new
163
+ @bullet_eager_loadings[record.class][record] << associations
164
+ end
165
+
166
+ result
167
+ end
168
+ end
169
+ )
170
+
171
+ ::ActiveRecord::Associations::Association.prepend(
172
+ Module.new do
173
+ def inversed_from(record)
174
+ if Bullet.start?
175
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
176
+ end
177
+ super
178
+ end
179
+
180
+ def inversed_from_queries(record)
181
+ if Bullet.start? && inversable?(record)
182
+ Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
183
+ end
184
+ super
185
+ end
186
+ end
187
+ )
188
+
189
+ ::ActiveRecord::Associations::CollectionAssociation.prepend(
190
+ Module.new do
191
+ def load_target
192
+ records = super
193
+
194
+ if Bullet.start?
195
+ if is_a? ::ActiveRecord::Associations::ThroughAssociation
196
+ association = owner.association(reflection.through_reflection.name)
197
+ if association.loaded?
198
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
199
+ Array.wrap(association.target).each do |through_record|
200
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
201
+ end
202
+
203
+ if reflection.through_reflection != through_reflection
204
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
205
+ end
206
+ end
207
+ end
208
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
209
+ if records.first.class.name !~ /^HABTM_/
210
+ if records.size > 1
211
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
212
+ Bullet::Detector::CounterCache.add_possible_objects(records)
213
+ elsif records.size == 1
214
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
215
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
216
+ end
217
+ end
218
+ end
219
+ records
220
+ end
221
+
222
+ def empty?
223
+ if Bullet.start? && !reflection.has_cached_counter?
224
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
225
+ end
226
+ super
227
+ end
228
+
229
+ def include?(object)
230
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
231
+ super
232
+ end
233
+ end
234
+ )
235
+
236
+ ::ActiveRecord::Associations::SingularAssociation.prepend(
237
+ Module.new do
238
+ # call has_one and belongs_to associations
239
+ def reader
240
+ result = super
241
+
242
+ if Bullet.start?
243
+ if owner.class.name !~ /^HABTM_/
244
+ if is_a? ::ActiveRecord::Associations::ThroughAssociation
245
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
246
+ association = owner.association(reflection.through_reflection.name)
247
+ Array.wrap(association.target).each do |through_record|
248
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
249
+ end
250
+
251
+ if reflection.through_reflection != through_reflection
252
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
253
+ end
254
+ end
255
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
256
+
257
+ if Bullet::Detector::NPlusOneQuery.impossible?(owner)
258
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
259
+ else
260
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
261
+ end
262
+ end
263
+ end
264
+ result
265
+ end
266
+ end
267
+ )
268
+
269
+ ::ActiveRecord::Associations::HasManyAssociation.prepend(
270
+ Module.new do
271
+ def empty?
272
+ result = super
273
+ if Bullet.start? && !reflection.has_cached_counter?
274
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
275
+ end
276
+ result
277
+ end
278
+
279
+ def count_records
280
+ result = reflection.has_cached_counter?
281
+ if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
282
+ Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
283
+ end
284
+ super
285
+ end
286
+ end
287
+ )
288
+
289
+ ::ActiveRecord::Associations::CollectionProxy.prepend(
290
+ Module.new do
291
+ def count(column_name = nil)
292
+ if Bullet.start? && !proxy_association.is_a?(::ActiveRecord::Associations::ThroughAssociation)
293
+ Bullet::Detector::CounterCache.add_counter_cache(
294
+ proxy_association.owner,
295
+ proxy_association.reflection.name
296
+ )
297
+ Bullet::Detector::NPlusOneQuery.call_association(
298
+ proxy_association.owner,
299
+ proxy_association.reflection.name
300
+ )
301
+ end
302
+ super(column_name)
303
+ end
304
+ end
305
+ )
306
+ end
307
+ end
308
+ 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
@@ -44,13 +44,10 @@ module Bullet
44
44
  unless obj.bullet_primary_key_value.nil?
45
45
  primary_key_values_are_empty = false
46
46
  end
47
- keys_joined += "#{(keys_joined.empty?? '' : ', ')}#{obj.bullet_key}"
47
+ keys_joined += "#{(keys_joined.empty? ? '' : ', ')}#{obj.bullet_key}"
48
48
  end
49
49
  unless class_names_match_regex || primary_key_values_are_empty
50
- Bullet.debug(
51
- 'Detector::NPlusOneQuery#add_possible_objects',
52
- "objects: #{keys_joined}"
53
- )
50
+ Bullet.debug('Detector::NPlusOneQuery#add_possible_objects', "objects: #{keys_joined}")
54
51
  objects.each { |object| possible_objects.add object.bullet_key }
55
52
  end
56
53
  end