bullet 6.1.3 → 7.0.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/.github/workflows/main.yml +82 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile.rails-7.0 +10 -0
- data/README.md +12 -10
- data/lib/bullet/active_record41.rb +1 -0
- data/lib/bullet/active_record42.rb +1 -0
- data/lib/bullet/active_record52.rb +11 -17
- data/lib/bullet/active_record60.rb +11 -17
- data/lib/bullet/active_record61.rb +11 -17
- data/lib/bullet/active_record70.rb +275 -0
- data/lib/bullet/bullet_xhr.js +1 -0
- data/lib/bullet/dependency.rb +10 -0
- data/lib/bullet/detector/base.rb +2 -1
- data/lib/bullet/detector/counter_cache.rb +1 -1
- data/lib/bullet/detector/n_plus_one_query.rb +3 -3
- data/lib/bullet/detector/unused_eager_loading.rb +1 -1
- data/lib/bullet/mongoid7x.rb +26 -9
- data/lib/bullet/notification.rb +2 -1
- data/lib/bullet/rack.rb +6 -3
- data/lib/bullet/stack_trace_filter.rb +7 -8
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +23 -24
- data/perf/benchmark.rb +4 -1
- data/spec/bullet/detector/unused_eager_loading_spec.rb +6 -2
- data/spec/bullet/ext/object_spec.rb +1 -1
- data/spec/bullet/rack_spec.rb +90 -13
- data/spec/bullet_spec.rb +15 -15
- data/spec/integration/active_record/association_spec.rb +27 -8
- data/spec/integration/counter_cache_spec.rb +4 -4
- data/spec/integration/mongoid/association_spec.rb +1 -1
- data/spec/models/deal.rb +5 -0
- data/spec/models/folder.rb +2 -1
- data/spec/models/group.rb +2 -1
- data/spec/models/page.rb +2 -1
- data/spec/models/post.rb +2 -0
- data/spec/models/role.rb +7 -0
- data/spec/models/user.rb +1 -0
- data/spec/models/writer.rb +2 -1
- data/spec/spec_helper.rb +0 -2
- data/spec/support/mongo_seed.rb +1 -0
- data/spec/support/sqlite_seed.rb +30 -0
- data/test.sh +2 -0
- metadata +10 -4
- data/.travis.yml +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 823bcc1af2be934ec4f10df71ea2951223834d3146e9c323afada99ba4ae4254
|
4
|
+
data.tar.gz: 4cda048b45bd219d62bee22e0041027561c943d283ee262ea71686a15e6e4345
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a2398eb23da7201bb8ab3fb1dbea3d48089d6c51d4a0e473d25009841aab41c68a5b0c27fb6ac6b77084e2465a836a5b848ffda63a2ea3b457a9571b04d428f
|
7
|
+
data.tar.gz: ab3debd03dc9cafbbd8ef9237f747c67d14bf3d8bf116b7dbed4e145176cf3f10045862b32641036e9bb00caca6eee841c75f9b3defad83ca681d0d70a5c6f0d
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: CI
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ master ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ master ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test_rails_4:
|
18
|
+
runs-on: ubuntu-latest
|
19
|
+
strategy:
|
20
|
+
matrix:
|
21
|
+
gemfile: ['Gemfile.rails-4.0', 'Gemfile.rails-4.1', 'Gemfile.rails-4.2']
|
22
|
+
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
23
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v2
|
26
|
+
- name: Set up Ruby
|
27
|
+
uses: ruby/setup-ruby@v1
|
28
|
+
with:
|
29
|
+
ruby-version: 2.3
|
30
|
+
bundler: 1
|
31
|
+
bundler-cache: true
|
32
|
+
- name: Run tests
|
33
|
+
run: bundle exec rake
|
34
|
+
test_rails_5:
|
35
|
+
runs-on: ubuntu-latest
|
36
|
+
strategy:
|
37
|
+
matrix:
|
38
|
+
gemfile: ['Gemfile.rails-5.0', 'Gemfile.rails-5.1', 'Gemfile.rails-5.2']
|
39
|
+
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
40
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
|
41
|
+
steps:
|
42
|
+
- uses: actions/checkout@v2
|
43
|
+
- name: Set up Ruby
|
44
|
+
uses: ruby/setup-ruby@v1
|
45
|
+
with:
|
46
|
+
ruby-version: 2.5
|
47
|
+
bundler: 1
|
48
|
+
bundler-cache: true
|
49
|
+
- name: Run tests
|
50
|
+
run: bundle exec rake
|
51
|
+
test_rails_6:
|
52
|
+
runs-on: ubuntu-latest
|
53
|
+
strategy:
|
54
|
+
matrix:
|
55
|
+
gemfile: ['Gemfile.rails-6.0', 'Gemfile.rails-6.1']
|
56
|
+
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
57
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
|
58
|
+
steps:
|
59
|
+
- uses: actions/checkout@v2
|
60
|
+
- name: Set up Ruby
|
61
|
+
uses: ruby/setup-ruby@v1
|
62
|
+
with:
|
63
|
+
ruby-version: 2.7
|
64
|
+
bundler-cache: true
|
65
|
+
- name: Run tests
|
66
|
+
run: bundle exec rake
|
67
|
+
test_rails_7:
|
68
|
+
runs-on: ubuntu-latest
|
69
|
+
strategy:
|
70
|
+
matrix:
|
71
|
+
gemfile: ['Gemfile.rails-7.0']
|
72
|
+
env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
|
73
|
+
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
|
74
|
+
steps:
|
75
|
+
- uses: actions/checkout@v2
|
76
|
+
- name: Set up Ruby
|
77
|
+
uses: ruby/setup-ruby@v1
|
78
|
+
with:
|
79
|
+
ruby-version: 3.1
|
80
|
+
bundler-cache: true
|
81
|
+
- name: Run tests
|
82
|
+
run: bundle exec rake
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
## Next Release
|
2
2
|
|
3
|
+
## 7.0.1 (01/15/2022)
|
4
|
+
|
5
|
+
* Get rid of *_whitelist methods
|
6
|
+
* Hack ActiveRecord::Associations::Preloader::Batch in rails 7
|
7
|
+
|
8
|
+
## 7.0.0 (12/18/2021)
|
9
|
+
|
10
|
+
* Support rails 7
|
11
|
+
* Fix Mongoid 7 view iteration
|
12
|
+
* Move CI from Travis to Github Actions
|
13
|
+
|
14
|
+
## 6.1.5 (08/16/2021)
|
15
|
+
|
16
|
+
* Rename whitelist to safelist
|
17
|
+
* Fix onload called twice
|
18
|
+
* Support Rack::Files::Iterator responses
|
19
|
+
* Ensure HABTM associations are not incorrectly labeled n+1
|
20
|
+
|
21
|
+
## 6.1.4 (02/26/2021)
|
22
|
+
|
23
|
+
* Added an option to stop adding HTTP headers to API requests
|
24
|
+
|
3
25
|
## 6.1.3 (01/21/2021)
|
4
26
|
|
5
27
|
* Consider ThroughAssociation at SingularAssociation like CollectionAssociation
|
data/Gemfile.rails-7.0
ADDED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Bullet
|
2
2
|
|
3
|
+

|
3
4
|
[](http://badge.fury.io/rb/bullet)
|
4
|
-
[](http://travis-ci.org/flyerhzm/bullet)
|
5
5
|
[](https://awesomecode.io/repos/flyerhzm/bullet)
|
6
6
|
[](http://coderwall.com/flyerhzm)
|
7
7
|
|
@@ -67,6 +67,7 @@ config.after_initialize do
|
|
67
67
|
Bullet.rails_logger = true
|
68
68
|
Bullet.honeybadger = true
|
69
69
|
Bullet.bugsnag = true
|
70
|
+
Bullet.appsignal = true
|
70
71
|
Bullet.airbrake = true
|
71
72
|
Bullet.rollbar = true
|
72
73
|
Bullet.add_footer = true
|
@@ -90,10 +91,12 @@ The code above will enable all of the Bullet notification systems:
|
|
90
91
|
* `Bullet.honeybadger`: add notifications to Honeybadger
|
91
92
|
* `Bullet.bugsnag`: add notifications to bugsnag
|
92
93
|
* `Bullet.airbrake`: add notifications to airbrake
|
94
|
+
* `Bullet.appsignal`: add notifications to AppSignal
|
93
95
|
* `Bullet.rollbar`: add notifications to rollbar
|
94
96
|
* `Bullet.sentry`: add notifications to sentry
|
95
97
|
* `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.
|
96
|
-
* `Bullet.skip_html_injection`: prevents Bullet from injecting
|
98
|
+
* `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.
|
99
|
+
* `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.
|
97
100
|
* `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
|
98
101
|
* `Bullet.stacktrace_excludes`: ignore paths with any of these substrings in the stack trace, even if they are not in your main app.
|
99
102
|
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
|
@@ -118,15 +121,15 @@ Bullet.unused_eager_loading_enable = false
|
|
118
121
|
Bullet.counter_cache_enable = false
|
119
122
|
```
|
120
123
|
|
121
|
-
##
|
124
|
+
## Safe list
|
122
125
|
|
123
126
|
Sometimes Bullet may notify you of query problems you don't care to fix, or
|
124
|
-
which come from outside your code. You can
|
127
|
+
which come from outside your code. You can add them to a safe list to ignore them:
|
125
128
|
|
126
129
|
```ruby
|
127
|
-
Bullet.
|
128
|
-
Bullet.
|
129
|
-
Bullet.
|
130
|
+
Bullet.add_safelist :type => :n_plus_one_query, :class_name => "Post", :association => :comments
|
131
|
+
Bullet.add_safelist :type => :unused_eager_loading, :class_name => "Post", :association => :comments
|
132
|
+
Bullet.add_safelist :type => :counter_cache, :class_name => "Country", :association => :cities
|
130
133
|
```
|
131
134
|
|
132
135
|
If you want to skip bullet in some specific controller actions, you can
|
@@ -267,8 +270,7 @@ Bullet outputs some details info, to enable debug mode, set
|
|
267
270
|
## Demo
|
268
271
|
|
269
272
|
Bullet is designed to function as you browse through your application in development. To see it in action,
|
270
|
-
you can
|
271
|
-
follow these steps to create, detect, and fix example query problems.
|
273
|
+
you can follow these steps to create, detect, and fix example query problems.
|
272
274
|
|
273
275
|
1\. Create an example application
|
274
276
|
|
@@ -479,4 +481,4 @@ Meanwhile, there's a line appended to `log/bullet.log`
|
|
479
481
|
Post => [:comments]
|
480
482
|
```
|
481
483
|
|
482
|
-
Copyright (c) 2009 -
|
484
|
+
Copyright (c) 2009 - 2022 Richard Huang (flyerhzm@gmail.com), released under the MIT license
|
@@ -30,6 +30,7 @@ module Bullet
|
|
30
30
|
|
31
31
|
::ActiveRecord::Relation.class_eval do
|
32
32
|
alias_method :origin_to_a, :to_a
|
33
|
+
|
33
34
|
# if select a collection of objects, then these objects have possible to cause N+1 query.
|
34
35
|
# if select only one object, then the only one object has impossible to cause N+1 query.
|
35
36
|
def to_a
|
@@ -52,6 +52,7 @@ module Bullet
|
|
52
52
|
|
53
53
|
::ActiveRecord::Relation.class_eval do
|
54
54
|
alias_method :origin_to_a, :to_a
|
55
|
+
|
55
56
|
# if select a collection of objects, then these objects have possible to cause N+1 query.
|
56
57
|
# if select only one object, then the only one object has impossible to cause N+1 query.
|
57
58
|
def to_a
|
@@ -75,23 +75,6 @@ module Bullet
|
|
75
75
|
end
|
76
76
|
)
|
77
77
|
|
78
|
-
::ActiveRecord::FinderMethods.prepend(
|
79
|
-
Module.new do
|
80
|
-
# add includes in scope
|
81
|
-
def find_with_associations
|
82
|
-
return super { |r| yield r } if block_given?
|
83
|
-
|
84
|
-
records = super
|
85
|
-
if Bullet.start?
|
86
|
-
associations = (eager_load_values + includes_values).uniq
|
87
|
-
records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
|
88
|
-
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
|
89
|
-
end
|
90
|
-
records
|
91
|
-
end
|
92
|
-
end
|
93
|
-
)
|
94
|
-
|
95
78
|
::ActiveRecord::Associations::JoinDependency.prepend(
|
96
79
|
Module.new do
|
97
80
|
def instantiate(result_set, &block)
|
@@ -149,6 +132,17 @@ module Bullet
|
|
149
132
|
end
|
150
133
|
)
|
151
134
|
|
135
|
+
::ActiveRecord::Associations::Association.prepend(
|
136
|
+
Module.new do
|
137
|
+
def inversed_from(record)
|
138
|
+
if Bullet.start?
|
139
|
+
Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
|
140
|
+
end
|
141
|
+
super
|
142
|
+
end
|
143
|
+
end
|
144
|
+
)
|
145
|
+
|
152
146
|
::ActiveRecord::Associations::CollectionAssociation.prepend(
|
153
147
|
Module.new do
|
154
148
|
def load_target
|
@@ -102,23 +102,6 @@ module Bullet
|
|
102
102
|
end
|
103
103
|
)
|
104
104
|
|
105
|
-
::ActiveRecord::FinderMethods.prepend(
|
106
|
-
Module.new do
|
107
|
-
# add includes in scope
|
108
|
-
def find_with_associations
|
109
|
-
return super { |r| yield r } if block_given?
|
110
|
-
|
111
|
-
records = super
|
112
|
-
if Bullet.start?
|
113
|
-
associations = (eager_load_values + includes_values).uniq
|
114
|
-
records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
|
115
|
-
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
|
116
|
-
end
|
117
|
-
records
|
118
|
-
end
|
119
|
-
end
|
120
|
-
)
|
121
|
-
|
122
105
|
::ActiveRecord::Associations::JoinDependency.prepend(
|
123
106
|
Module.new do
|
124
107
|
def instantiate(result_set, &block)
|
@@ -176,6 +159,17 @@ module Bullet
|
|
176
159
|
end
|
177
160
|
)
|
178
161
|
|
162
|
+
::ActiveRecord::Associations::Association.prepend(
|
163
|
+
Module.new do
|
164
|
+
def inversed_from(record)
|
165
|
+
if Bullet.start?
|
166
|
+
Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
|
167
|
+
end
|
168
|
+
super
|
169
|
+
end
|
170
|
+
end
|
171
|
+
)
|
172
|
+
|
179
173
|
::ActiveRecord::Associations::CollectionAssociation.prepend(
|
180
174
|
Module.new do
|
181
175
|
def load_target
|
@@ -102,23 +102,6 @@ module Bullet
|
|
102
102
|
end
|
103
103
|
)
|
104
104
|
|
105
|
-
::ActiveRecord::FinderMethods.prepend(
|
106
|
-
Module.new do
|
107
|
-
# add includes in scope
|
108
|
-
def find_with_associations
|
109
|
-
return super { |r| yield r } if block_given?
|
110
|
-
|
111
|
-
records = super
|
112
|
-
if Bullet.start?
|
113
|
-
associations = (eager_load_values + includes_values).uniq
|
114
|
-
records.each { |record| Bullet::Detector::Association.add_object_associations(record, associations) }
|
115
|
-
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
|
116
|
-
end
|
117
|
-
records
|
118
|
-
end
|
119
|
-
end
|
120
|
-
)
|
121
|
-
|
122
105
|
::ActiveRecord::Associations::JoinDependency.prepend(
|
123
106
|
Module.new do
|
124
107
|
def instantiate(result_set, strict_loading_value, &block)
|
@@ -176,6 +159,17 @@ module Bullet
|
|
176
159
|
end
|
177
160
|
)
|
178
161
|
|
162
|
+
::ActiveRecord::Associations::Association.prepend(
|
163
|
+
Module.new do
|
164
|
+
def inversed_from(record)
|
165
|
+
if Bullet.start?
|
166
|
+
Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
|
167
|
+
end
|
168
|
+
super
|
169
|
+
end
|
170
|
+
end
|
171
|
+
)
|
172
|
+
|
179
173
|
::ActiveRecord::Associations::CollectionAssociation.prepend(
|
180
174
|
Module.new do
|
181
175
|
def load_target
|
@@ -0,0 +1,275 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bullet
|
4
|
+
module SaveWithBulletSupport
|
5
|
+
def _create_record(*)
|
6
|
+
super do
|
7
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
8
|
+
yield(self) if block_given?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ActiveRecord
|
14
|
+
def self.enable
|
15
|
+
require 'active_record'
|
16
|
+
::ActiveRecord::Base.extend(
|
17
|
+
Module.new do
|
18
|
+
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
19
|
+
result = super
|
20
|
+
if Bullet.start?
|
21
|
+
if result.is_a? Array
|
22
|
+
if result.size > 1
|
23
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
24
|
+
Bullet::Detector::CounterCache.add_possible_objects(result)
|
25
|
+
elsif result.size == 1
|
26
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
|
27
|
+
Bullet::Detector::CounterCache.add_impossible_object(result.first)
|
28
|
+
end
|
29
|
+
elsif result.is_a? ::ActiveRecord::Base
|
30
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
|
31
|
+
Bullet::Detector::CounterCache.add_impossible_object(result)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
result
|
35
|
+
end
|
36
|
+
end
|
37
|
+
)
|
38
|
+
|
39
|
+
::ActiveRecord::Base.prepend(SaveWithBulletSupport)
|
40
|
+
|
41
|
+
::ActiveRecord::Relation.prepend(
|
42
|
+
Module.new do
|
43
|
+
# if select a collection of objects, then these objects have possible to cause N+1 query.
|
44
|
+
# if select only one object, then the only one object has impossible to cause N+1 query.
|
45
|
+
def records
|
46
|
+
result = super
|
47
|
+
if Bullet.start?
|
48
|
+
if result.first.class.name !~ /^HABTM_/
|
49
|
+
if result.size > 1
|
50
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
51
|
+
Bullet::Detector::CounterCache.add_possible_objects(result)
|
52
|
+
elsif result.size == 1
|
53
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
|
54
|
+
Bullet::Detector::CounterCache.add_impossible_object(result.first)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
)
|
62
|
+
|
63
|
+
::ActiveRecord::Associations::Preloader::Batch.prepend(
|
64
|
+
Module.new do
|
65
|
+
def call
|
66
|
+
if Bullet.start?
|
67
|
+
@preloaders.each do |preloader|
|
68
|
+
preloader.records.each { |record| Bullet::Detector::Association.add_object_associations(record, preloader.associations) }
|
69
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(preloader.records, preloader.associations)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
super
|
73
|
+
end
|
74
|
+
end
|
75
|
+
)
|
76
|
+
|
77
|
+
::ActiveRecord::Associations::Preloader::Branch.prepend(
|
78
|
+
Module.new do
|
79
|
+
def preloaders_for_reflection(reflection, reflection_records)
|
80
|
+
if Bullet.start?
|
81
|
+
reflection_records.compact!
|
82
|
+
if reflection_records.first.class.name !~ /^HABTM_/
|
83
|
+
reflection_records.each { |record| Bullet::Detector::Association.add_object_associations(record, reflection.name) }
|
84
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(reflection_records, reflection.name)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
)
|
91
|
+
|
92
|
+
::ActiveRecord::Associations::Preloader::ThroughAssociation.prepend(
|
93
|
+
Module.new do
|
94
|
+
def 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|
|
99
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection_name)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
super
|
104
|
+
end
|
105
|
+
end
|
106
|
+
)
|
107
|
+
|
108
|
+
::ActiveRecord::Associations::JoinDependency.prepend(
|
109
|
+
Module.new do
|
110
|
+
def instantiate(result_set, strict_loading_value, &block)
|
111
|
+
@bullet_eager_loadings = {}
|
112
|
+
records = super
|
113
|
+
|
114
|
+
if Bullet.start?
|
115
|
+
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
116
|
+
objects = eager_loadings_hash.keys
|
117
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(
|
118
|
+
objects,
|
119
|
+
eager_loadings_hash[objects.first].to_a
|
120
|
+
)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
records
|
124
|
+
end
|
125
|
+
|
126
|
+
def construct(ar_parent, parent, row, seen, model_cache, strict_loading_value)
|
127
|
+
if Bullet.start?
|
128
|
+
unless ar_parent.nil?
|
129
|
+
parent.children.each do |node|
|
130
|
+
key = aliases.column_alias(node, node.primary_key)
|
131
|
+
id = row[key]
|
132
|
+
next unless id.nil?
|
133
|
+
|
134
|
+
associations = node.reflection.name
|
135
|
+
Bullet::Detector::Association.add_object_associations(ar_parent, associations)
|
136
|
+
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
|
137
|
+
@bullet_eager_loadings[ar_parent.class] ||= {}
|
138
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
|
139
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] << associations
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
super
|
145
|
+
end
|
146
|
+
|
147
|
+
# call join associations
|
148
|
+
def construct_model(record, node, row, model_cache, id, strict_loading_value)
|
149
|
+
result = super
|
150
|
+
|
151
|
+
if Bullet.start?
|
152
|
+
associations = node.reflection.name
|
153
|
+
Bullet::Detector::Association.add_object_associations(record, associations)
|
154
|
+
Bullet::Detector::NPlusOneQuery.call_association(record, associations)
|
155
|
+
@bullet_eager_loadings[record.class] ||= {}
|
156
|
+
@bullet_eager_loadings[record.class][record] ||= Set.new
|
157
|
+
@bullet_eager_loadings[record.class][record] << associations
|
158
|
+
end
|
159
|
+
|
160
|
+
result
|
161
|
+
end
|
162
|
+
end
|
163
|
+
)
|
164
|
+
|
165
|
+
::ActiveRecord::Associations::Association.prepend(
|
166
|
+
Module.new do
|
167
|
+
def inversed_from(record)
|
168
|
+
if Bullet.start?
|
169
|
+
Bullet::Detector::NPlusOneQuery.add_inversed_object(owner, reflection.name)
|
170
|
+
end
|
171
|
+
super
|
172
|
+
end
|
173
|
+
end
|
174
|
+
)
|
175
|
+
|
176
|
+
::ActiveRecord::Associations::CollectionAssociation.prepend(
|
177
|
+
Module.new do
|
178
|
+
def load_target
|
179
|
+
records = super
|
180
|
+
|
181
|
+
if Bullet.start?
|
182
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
183
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
184
|
+
association = owner.association(reflection.through_reflection.name)
|
185
|
+
Array(association.target).each do |through_record|
|
186
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
187
|
+
end
|
188
|
+
|
189
|
+
if reflection.through_reflection != through_reflection
|
190
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
194
|
+
if records.first.class.name !~ /^HABTM_/
|
195
|
+
if records.size > 1
|
196
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
|
197
|
+
Bullet::Detector::CounterCache.add_possible_objects(records)
|
198
|
+
elsif records.size == 1
|
199
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
|
200
|
+
Bullet::Detector::CounterCache.add_impossible_object(records.first)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
records
|
205
|
+
end
|
206
|
+
|
207
|
+
def empty?
|
208
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
209
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
210
|
+
end
|
211
|
+
super
|
212
|
+
end
|
213
|
+
|
214
|
+
def include?(object)
|
215
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet.start?
|
216
|
+
super
|
217
|
+
end
|
218
|
+
end
|
219
|
+
)
|
220
|
+
|
221
|
+
::ActiveRecord::Associations::SingularAssociation.prepend(
|
222
|
+
Module.new do
|
223
|
+
# call has_one and belongs_to associations
|
224
|
+
def reader
|
225
|
+
result = super
|
226
|
+
|
227
|
+
if Bullet.start?
|
228
|
+
if owner.class.name !~ /^HABTM_/
|
229
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
230
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
231
|
+
association = owner.association(reflection.through_reflection.name)
|
232
|
+
Array(association.target).each do |through_record|
|
233
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
234
|
+
end
|
235
|
+
|
236
|
+
if reflection.through_reflection != through_reflection
|
237
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
241
|
+
|
242
|
+
if Bullet::Detector::NPlusOneQuery.impossible?(owner)
|
243
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
|
244
|
+
else
|
245
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
result
|
250
|
+
end
|
251
|
+
end
|
252
|
+
)
|
253
|
+
|
254
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(
|
255
|
+
Module.new do
|
256
|
+
def empty?
|
257
|
+
result = super
|
258
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
259
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
260
|
+
end
|
261
|
+
result
|
262
|
+
end
|
263
|
+
|
264
|
+
def count_records
|
265
|
+
result = reflection.has_cached_counter?
|
266
|
+
if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
267
|
+
Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
|
268
|
+
end
|
269
|
+
super
|
270
|
+
end
|
271
|
+
end
|
272
|
+
)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
data/lib/bullet/bullet_xhr.js
CHANGED
data/lib/bullet/dependency.rb
CHANGED
@@ -29,6 +29,8 @@ module Bullet
|
|
29
29
|
'active_record60'
|
30
30
|
elsif active_record61?
|
31
31
|
'active_record61'
|
32
|
+
elsif active_record70?
|
33
|
+
'active_record70'
|
32
34
|
else
|
33
35
|
raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
|
34
36
|
end
|
@@ -64,6 +66,10 @@ module Bullet
|
|
64
66
|
active_record? && ::ActiveRecord::VERSION::MAJOR == 6
|
65
67
|
end
|
66
68
|
|
69
|
+
def active_record7?
|
70
|
+
active_record? && ::ActiveRecord::VERSION::MAJOR == 7
|
71
|
+
end
|
72
|
+
|
67
73
|
def active_record40?
|
68
74
|
active_record4? && ::ActiveRecord::VERSION::MINOR == 0
|
69
75
|
end
|
@@ -96,6 +102,10 @@ module Bullet
|
|
96
102
|
active_record6? && ::ActiveRecord::VERSION::MINOR == 1
|
97
103
|
end
|
98
104
|
|
105
|
+
def active_record70?
|
106
|
+
active_record7? && ::ActiveRecord::VERSION::MINOR == 0
|
107
|
+
end
|
108
|
+
|
99
109
|
def mongoid4x?
|
100
110
|
mongoid? && ::Mongoid::VERSION =~ /\A4/
|
101
111
|
end
|
data/lib/bullet/detector/base.rb
CHANGED
@@ -54,7 +54,7 @@ module Bullet
|
|
54
54
|
private
|
55
55
|
|
56
56
|
def create_notification(klazz, associations)
|
57
|
-
notify_associations = Array(associations) - Bullet.
|
57
|
+
notify_associations = Array(associations) - Bullet.get_safelist_associations(:counter_cache, klazz)
|
58
58
|
|
59
59
|
if notify_associations.present?
|
60
60
|
notice = Bullet::Notification::CounterCache.new klazz, notify_associations
|