bullet 6.1.0 → 7.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +82 -0
- data/CHANGELOG.md +66 -0
- data/Gemfile.rails-6.0 +1 -1
- data/Gemfile.rails-6.1 +15 -0
- data/Gemfile.rails-7.0 +10 -0
- data/MIT-LICENSE +1 -1
- data/README.md +41 -27
- data/lib/bullet/active_job.rb +5 -1
- data/lib/bullet/active_record41.rb +1 -0
- data/lib/bullet/active_record42.rb +1 -0
- data/lib/bullet/active_record5.rb +10 -8
- data/lib/bullet/active_record52.rb +32 -25
- data/lib/bullet/active_record60.rb +30 -23
- data/lib/bullet/active_record61.rb +274 -0
- data/lib/bullet/active_record70.rb +284 -0
- data/lib/bullet/bullet_xhr.js +18 -17
- data/lib/bullet/dependency.rb +16 -0
- data/lib/bullet/detector/association.rb +8 -0
- data/lib/bullet/detector/base.rb +2 -1
- data/lib/bullet/detector/counter_cache.rb +2 -2
- data/lib/bullet/detector/n_plus_one_query.rb +24 -13
- data/lib/bullet/detector/unused_eager_loading.rb +3 -3
- data/lib/bullet/mongoid4x.rb +1 -1
- data/lib/bullet/mongoid5x.rb +1 -1
- data/lib/bullet/mongoid6x.rb +1 -1
- data/lib/bullet/mongoid7x.rb +32 -17
- data/lib/bullet/notification.rb +2 -1
- data/lib/bullet/rack.rb +64 -23
- data/lib/bullet/registry/call_stack.rb +12 -0
- data/lib/bullet/registry.rb +1 -0
- data/lib/bullet/stack_trace_filter.rb +15 -15
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +35 -29
- data/lib/generators/bullet/install_generator.rb +22 -25
- data/perf/benchmark.rb +4 -1
- data/spec/bullet/detector/counter_cache_spec.rb +1 -1
- data/spec/bullet/detector/n_plus_one_query_spec.rb +1 -33
- data/spec/bullet/detector/unused_eager_loading_spec.rb +15 -10
- data/spec/bullet/ext/object_spec.rb +1 -1
- data/spec/bullet/notification/base_spec.rb +4 -4
- data/spec/bullet/notification/n_plus_one_query_spec.rb +1 -3
- data/spec/bullet/rack_spec.rb +152 -9
- data/spec/bullet/stack_trace_filter_spec.rb +26 -0
- data/spec/bullet_spec.rb +15 -15
- data/spec/integration/active_record/association_spec.rb +95 -12
- data/spec/integration/counter_cache_spec.rb +4 -4
- data/spec/integration/mongoid/association_spec.rb +4 -4
- data/spec/models/attachment.rb +5 -0
- 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/submission.rb +1 -0
- data/spec/models/user.rb +2 -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 +38 -0
- data/test.sh +2 -0
- metadata +20 -7
- 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: 0f47e147f5df074217ee7a65123f54a1918f98bde162c7d4bf1f76bffc9f15a6
|
4
|
+
data.tar.gz: e05e48b96a5e68bfbcac63f4dce4601d717ec1a32ee83a5c45aad738e1bfc48b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87bf095754befedb8f1137ae039191807baa1f1bcadb09c923b4f1a6abd385e73e4143e50077358a8f7155e3bf367edb1b405e3b0b260c8de5dd572699b7bafc
|
7
|
+
data.tar.gz: fd692ae67a1695ee4598b24d3cd030a7f091deb42f30df0f92085b3c54f765960c0b5eabaace7b306fadf8539b514fe77076cff825c27a292c5e36f56916646b
|
@@ -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: [ main ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ main ]
|
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,71 @@
|
|
1
1
|
## Next Release
|
2
2
|
|
3
|
+
## 7.0.7 (03/01/2023)
|
4
|
+
|
5
|
+
* Check `Rails.application.config.content_security_policy` before insert `Bullet::Rack`
|
6
|
+
|
7
|
+
## 7.0.6 (03/01/2023)
|
8
|
+
|
9
|
+
* Better way to check if `ActionDispatch::ContentSecurityPolicy::Middleware` exists
|
10
|
+
|
11
|
+
## 7.0.5 (01/01/2023)
|
12
|
+
|
13
|
+
* Fix n+1 false positives in AR 7.0
|
14
|
+
* Fix eager_load nested has_many :through false positives
|
15
|
+
* Respect Content-Security-Policy nonces
|
16
|
+
* Added CallStacks support for avoid eager loading
|
17
|
+
* Iterate fewer times over objects
|
18
|
+
|
19
|
+
## 7.0.4 (11/28/2022)
|
20
|
+
|
21
|
+
* Fix `eager_load` `has_many :through` false positives
|
22
|
+
* mongoid7x: add dynamic methods
|
23
|
+
|
24
|
+
## 7.0.3 (08/13/2022)
|
25
|
+
|
26
|
+
* Replace `Array()` with `Array.wrap()`
|
27
|
+
|
28
|
+
## 7.0.2 (05/31/2022)
|
29
|
+
|
30
|
+
* Drop growl support
|
31
|
+
* Do not check html tag in Bullet::Rack anymore
|
32
|
+
|
33
|
+
## 7.0.1 (01/15/2022)
|
34
|
+
|
35
|
+
* Get rid of *_whitelist methods
|
36
|
+
* Hack ActiveRecord::Associations::Preloader::Batch in rails 7
|
37
|
+
|
38
|
+
## 7.0.0 (12/18/2021)
|
39
|
+
|
40
|
+
* Support rails 7
|
41
|
+
* Fix Mongoid 7 view iteration
|
42
|
+
* Move CI from Travis to Github Actions
|
43
|
+
|
44
|
+
## 6.1.5 (08/16/2021)
|
45
|
+
|
46
|
+
* Rename whitelist to safelist
|
47
|
+
* Fix onload called twice
|
48
|
+
* Support Rack::Files::Iterator responses
|
49
|
+
* Ensure HABTM associations are not incorrectly labeled n+1
|
50
|
+
|
51
|
+
## 6.1.4 (02/26/2021)
|
52
|
+
|
53
|
+
* Added an option to stop adding HTTP headers to API requests
|
54
|
+
|
55
|
+
## 6.1.3 (01/21/2021)
|
56
|
+
|
57
|
+
* Consider ThroughAssociation at SingularAssociation like CollectionAssociation
|
58
|
+
* Add xhr_script only when add_footer is enabled
|
59
|
+
|
60
|
+
## 6.1.2 (12/12/2020)
|
61
|
+
|
62
|
+
* Revert "Make whitelist thread safe"
|
63
|
+
|
64
|
+
## 6.1.1 (12/12/2020)
|
65
|
+
|
66
|
+
* Add support Rails 6.1
|
67
|
+
* Make whitelist thread safe
|
68
|
+
|
3
69
|
## 6.1.0 (12/28/2019)
|
4
70
|
|
5
71
|
* Add skip_html_injection flag
|
data/Gemfile.rails-6.0
CHANGED
data/Gemfile.rails-6.1
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
gem 'rails', '~> 6.1.0'
|
6
|
+
gem 'sqlite3'
|
7
|
+
gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
|
8
|
+
gem 'activerecord-import'
|
9
|
+
|
10
|
+
gem "rspec"
|
11
|
+
|
12
|
+
platforms :rbx do
|
13
|
+
gem 'rubysl', '~> 2.0'
|
14
|
+
gem 'rubinius-developer_tools'
|
15
|
+
end
|
data/Gemfile.rails-7.0
ADDED
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Bullet
|
2
2
|
|
3
|
+
![Main workflow](https://github.com/flyerhzm/bullet/actions/workflows/main.yml/badge.svg)
|
3
4
|
[![Gem Version](https://badge.fury.io/rb/bullet.svg)](http://badge.fury.io/rb/bullet)
|
4
|
-
[![Build Status](https://secure.travis-ci.org/flyerhzm/bullet.svg)](http://travis-ci.org/flyerhzm/bullet)
|
5
5
|
[![AwesomeCode Status for flyerhzm/bullet](https://awesomecode.io/projects/6755235b-e2c1-459e-bf92-b8b13d0c0472/status)](https://awesomecode.io/repos/flyerhzm/bullet)
|
6
6
|
[![Coderwall Endorse](http://api.coderwall.com/flyerhzm/endorsecount.png)](http://coderwall.com/flyerhzm)
|
7
7
|
|
@@ -37,12 +37,19 @@ or add it into a Gemfile (Bundler):
|
|
37
37
|
gem 'bullet', group: 'development'
|
38
38
|
```
|
39
39
|
|
40
|
+
enable the Bullet gem with generate command
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
bundle exec rails g bullet:install
|
44
|
+
```
|
45
|
+
The generate command will auto generate the default configuration and may ask to include in the test environment as well. See below for custom configuration.
|
46
|
+
|
40
47
|
**Note**: make sure `bullet` gem is added after activerecord (rails) and
|
41
48
|
mongoid.
|
42
49
|
|
43
50
|
## Configuration
|
44
51
|
|
45
|
-
Bullet won't
|
52
|
+
Bullet won't enable any notification systems unless you tell it to explicitly. Append to
|
46
53
|
`config/environments/development.rb` initializer with the following code:
|
47
54
|
|
48
55
|
```ruby
|
@@ -52,7 +59,6 @@ config.after_initialize do
|
|
52
59
|
Bullet.alert = true
|
53
60
|
Bullet.bullet_logger = true
|
54
61
|
Bullet.console = true
|
55
|
-
Bullet.growl = true
|
56
62
|
Bullet.xmpp = { :account => 'bullets_account@jabber.org',
|
57
63
|
:password => 'bullets_password_for_jabber',
|
58
64
|
:receiver => 'your_account@jabber.org',
|
@@ -60,6 +66,7 @@ config.after_initialize do
|
|
60
66
|
Bullet.rails_logger = true
|
61
67
|
Bullet.honeybadger = true
|
62
68
|
Bullet.bugsnag = true
|
69
|
+
Bullet.appsignal = true
|
63
70
|
Bullet.airbrake = true
|
64
71
|
Bullet.rollbar = true
|
65
72
|
Bullet.add_footer = true
|
@@ -77,16 +84,17 @@ The code above will enable all of the Bullet notification systems:
|
|
77
84
|
* `Bullet.alert`: pop up a JavaScript alert in the browser
|
78
85
|
* `Bullet.bullet_logger`: log to the Bullet log file (Rails.root/log/bullet.log)
|
79
86
|
* `Bullet.console`: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
|
80
|
-
* `Bullet.growl`: pop up Growl warnings if your system has Growl installed. Requires a little bit of configuration
|
81
87
|
* `Bullet.xmpp`: send XMPP/Jabber notifications to the receiver indicated. Note that the code will currently not handle the adding of contacts, so you will need to make both accounts indicated know each other manually before you will receive any notifications. If you restart the development server frequently, the 'coming online' sound for the Bullet account may start to annoy - in this case set :show_online_status to false; you will still get notifications, but the Bullet account won't announce it's online status anymore.
|
82
88
|
* `Bullet.rails_logger`: add warnings directly to the Rails log
|
83
89
|
* `Bullet.honeybadger`: add notifications to Honeybadger
|
84
90
|
* `Bullet.bugsnag`: add notifications to bugsnag
|
85
91
|
* `Bullet.airbrake`: add notifications to airbrake
|
92
|
+
* `Bullet.appsignal`: add notifications to AppSignal
|
86
93
|
* `Bullet.rollbar`: add notifications to rollbar
|
87
94
|
* `Bullet.sentry`: add notifications to sentry
|
88
95
|
* `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.
|
89
|
-
* `Bullet.skip_html_injection`: prevents Bullet from injecting
|
96
|
+
* `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.
|
97
|
+
* `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.
|
90
98
|
* `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
|
91
99
|
* `Bullet.stacktrace_excludes`: ignore paths with any of these substrings in the stack trace, even if they are not in your main app.
|
92
100
|
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
|
@@ -111,15 +119,15 @@ Bullet.unused_eager_loading_enable = false
|
|
111
119
|
Bullet.counter_cache_enable = false
|
112
120
|
```
|
113
121
|
|
114
|
-
##
|
122
|
+
## Safe list
|
115
123
|
|
116
124
|
Sometimes Bullet may notify you of query problems you don't care to fix, or
|
117
|
-
which come from outside your code. You can
|
125
|
+
which come from outside your code. You can add them to a safe list to ignore them:
|
118
126
|
|
119
127
|
```ruby
|
120
|
-
Bullet.
|
121
|
-
Bullet.
|
122
|
-
Bullet.
|
128
|
+
Bullet.add_safelist :type => :n_plus_one_query, :class_name => "Post", :association => :comments
|
129
|
+
Bullet.add_safelist :type => :unused_eager_loading, :class_name => "Post", :association => :comments
|
130
|
+
Bullet.add_safelist :type => :counter_cache, :class_name => "Country", :association => :cities
|
123
131
|
```
|
124
132
|
|
125
133
|
If you want to skip bullet in some specific controller actions, you can
|
@@ -146,25 +154,26 @@ The Bullet log `log/bullet.log` will look something like this:
|
|
146
154
|
* N+1 Query:
|
147
155
|
|
148
156
|
```
|
149
|
-
2009-08-25 20:40:17[INFO]
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
/Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `each'
|
154
|
-
/Users/richard/Downloads/test/app/
|
155
|
-
/Users/richard/Downloads/test/app/controllers/posts_controller.rb:7:in `index'
|
157
|
+
2009-08-25 20:40:17[INFO] USE eager loading detected:
|
158
|
+
Post => [:comments]·
|
159
|
+
Add to your query: .includes([:comments])
|
160
|
+
2009-08-25 20:40:17[INFO] Call stack
|
161
|
+
/Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `each'
|
162
|
+
/Users/richard/Downloads/test/app/controllers/posts_controller.rb:7:in `index'
|
156
163
|
```
|
157
164
|
|
158
|
-
The first
|
165
|
+
The first log entry is a notification that N+1 queries have been encountered. The remaining entry is a stack trace so you can find exactly where the queries were invoked in your code, and fix them.
|
159
166
|
|
160
167
|
* Unused eager loading:
|
161
168
|
|
162
169
|
```
|
163
|
-
2009-08-25 20:53:56[INFO]
|
164
|
-
|
170
|
+
2009-08-25 20:53:56[INFO] AVOID eager loading detected
|
171
|
+
Post => [:comments]·
|
172
|
+
Remove from your query: .includes([:comments])
|
173
|
+
2009-08-25 20:53:56[INFO] Call stack
|
165
174
|
```
|
166
175
|
|
167
|
-
These
|
176
|
+
These lines are notifications that unused eager loadings have been encountered.
|
168
177
|
|
169
178
|
* Need counter cache:
|
170
179
|
|
@@ -173,10 +182,14 @@ These two lines are notifications that unused eager loadings have been encounter
|
|
173
182
|
Post => [:comments]
|
174
183
|
```
|
175
184
|
|
176
|
-
##
|
185
|
+
## XMPP/Jabber and Airbrake Support
|
177
186
|
|
178
187
|
see [https://github.com/flyerhzm/uniform_notifier](https://github.com/flyerhzm/uniform_notifier)
|
179
188
|
|
189
|
+
## Growl Support
|
190
|
+
|
191
|
+
Growl support is dropped from uniform_notifier 1.16.0, if you still want it, please use uniform_notifier 1.15.0.
|
192
|
+
|
180
193
|
## Important
|
181
194
|
|
182
195
|
If you find Bullet does not work for you, *please disable your browser's cache*.
|
@@ -209,7 +222,7 @@ end
|
|
209
222
|
|
210
223
|
### Work with sinatra
|
211
224
|
|
212
|
-
Configure and use `Bullet::Rack
|
225
|
+
Configure and use `Bullet::Rack`.
|
213
226
|
|
214
227
|
```ruby
|
215
228
|
configure :development do
|
@@ -219,6 +232,8 @@ configure :development do
|
|
219
232
|
end
|
220
233
|
```
|
221
234
|
|
235
|
+
If your application generates a Content-Security-Policy via a separate middleware, ensure that `Bullet::Rack` is loaded _before_ that middleware.
|
236
|
+
|
222
237
|
### Run in tests
|
223
238
|
|
224
239
|
First you need to enable Bullet in test environment.
|
@@ -260,8 +275,7 @@ Bullet outputs some details info, to enable debug mode, set
|
|
260
275
|
## Demo
|
261
276
|
|
262
277
|
Bullet is designed to function as you browse through your application in development. To see it in action,
|
263
|
-
you can
|
264
|
-
follow these steps to create, detect, and fix example query problems.
|
278
|
+
you can follow these steps to create, detect, and fix example query problems.
|
265
279
|
|
266
280
|
1\. Create an example application
|
267
281
|
|
@@ -273,7 +287,7 @@ $ rails g scaffold comment name:string post_id:integer
|
|
273
287
|
$ bundle exec rake db:migrate
|
274
288
|
```
|
275
289
|
|
276
|
-
2\. Change `app/
|
290
|
+
2\. Change `app/models/post.rb` and `app/models/comment.rb`
|
277
291
|
|
278
292
|
```ruby
|
279
293
|
class Post < ActiveRecord::Base
|
@@ -472,4 +486,4 @@ Meanwhile, there's a line appended to `log/bullet.log`
|
|
472
486
|
Post => [:comments]
|
473
487
|
```
|
474
488
|
|
475
|
-
Copyright (c) 2009 -
|
489
|
+
Copyright (c) 2009 - 2022 Richard Huang (flyerhzm@gmail.com), released under the MIT license
|
data/lib/bullet/active_job.rb
CHANGED
@@ -3,7 +3,11 @@
|
|
3
3
|
module Bullet
|
4
4
|
module ActiveJob
|
5
5
|
def self.included(base)
|
6
|
-
base.class_eval
|
6
|
+
base.class_eval do
|
7
|
+
around_perform do |_job, block|
|
8
|
+
Bullet.profile { block.call }
|
9
|
+
end
|
10
|
+
end
|
7
11
|
end
|
8
12
|
end
|
9
13
|
end
|
@@ -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
|
@@ -177,16 +177,18 @@ module Bullet
|
|
177
177
|
if Bullet.start?
|
178
178
|
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
179
179
|
refl = reflection.through_reflection
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
180
|
+
association = owner.association(refl.name)
|
181
|
+
if association.loaded?
|
182
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
|
183
|
+
Array.wrap(association.target).each do |through_record|
|
184
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
185
|
+
end
|
185
186
|
|
186
|
-
|
187
|
-
|
187
|
+
if refl.through_reflection?
|
188
|
+
refl = refl.through_reflection while refl.through_reflection?
|
188
189
|
|
189
|
-
|
190
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
|
191
|
+
end
|
190
192
|
end
|
191
193
|
end
|
192
194
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
@@ -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
|
@@ -156,14 +150,16 @@ module Bullet
|
|
156
150
|
|
157
151
|
if Bullet.start?
|
158
152
|
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
153
|
+
association = owner.association(reflection.through_reflection.name)
|
154
|
+
if association.loaded?
|
155
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
156
|
+
Array.wrap(association.target).each do |through_record|
|
157
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
158
|
+
end
|
159
|
+
|
160
|
+
if reflection.through_reflection != through_reflection
|
161
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
162
|
+
end
|
167
163
|
end
|
168
164
|
end
|
169
165
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
@@ -202,6 +198,17 @@ module Bullet
|
|
202
198
|
|
203
199
|
if Bullet.start?
|
204
200
|
if owner.class.name !~ /^HABTM_/ && !@inversed
|
201
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
202
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
203
|
+
association = owner.association reflection.through_reflection.name
|
204
|
+
Array.wrap(association.target).each do |through_record|
|
205
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
206
|
+
end
|
207
|
+
|
208
|
+
if reflection.through_reflection != through_reflection
|
209
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
210
|
+
end
|
211
|
+
end
|
205
212
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
206
213
|
|
207
214
|
if Bullet::Detector::NPlusOneQuery.impossible?(owner)
|
@@ -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
|
@@ -183,14 +177,16 @@ module Bullet
|
|
183
177
|
|
184
178
|
if Bullet.start?
|
185
179
|
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
186
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
187
180
|
association = owner.association(reflection.through_reflection.name)
|
188
|
-
|
189
|
-
Bullet::Detector::NPlusOneQuery.call_association(
|
190
|
-
|
181
|
+
if association.loaded?
|
182
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
183
|
+
Array.wrap(association.target).each do |through_record|
|
184
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
185
|
+
end
|
191
186
|
|
192
|
-
|
193
|
-
|
187
|
+
if reflection.through_reflection != through_reflection
|
188
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
189
|
+
end
|
194
190
|
end
|
195
191
|
end
|
196
192
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
@@ -229,6 +225,17 @@ module Bullet
|
|
229
225
|
|
230
226
|
if Bullet.start?
|
231
227
|
if owner.class.name !~ /^HABTM_/ && !@inversed
|
228
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
229
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
230
|
+
association = owner.association(reflection.through_reflection.name)
|
231
|
+
Array.wrap(association.target).each do |through_record|
|
232
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
233
|
+
end
|
234
|
+
|
235
|
+
if reflection.through_reflection != through_reflection
|
236
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
237
|
+
end
|
238
|
+
end
|
232
239
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
233
240
|
|
234
241
|
if Bullet::Detector::NPlusOneQuery.impossible?(owner)
|