bullet 6.1.0 → 7.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +82 -0
  3. data/CHANGELOG.md +66 -0
  4. data/Gemfile.rails-6.0 +1 -1
  5. data/Gemfile.rails-6.1 +15 -0
  6. data/Gemfile.rails-7.0 +10 -0
  7. data/MIT-LICENSE +1 -1
  8. data/README.md +41 -27
  9. data/lib/bullet/active_job.rb +5 -1
  10. data/lib/bullet/active_record41.rb +1 -0
  11. data/lib/bullet/active_record42.rb +1 -0
  12. data/lib/bullet/active_record5.rb +10 -8
  13. data/lib/bullet/active_record52.rb +32 -25
  14. data/lib/bullet/active_record60.rb +30 -23
  15. data/lib/bullet/active_record61.rb +274 -0
  16. data/lib/bullet/active_record70.rb +284 -0
  17. data/lib/bullet/bullet_xhr.js +18 -17
  18. data/lib/bullet/dependency.rb +16 -0
  19. data/lib/bullet/detector/association.rb +8 -0
  20. data/lib/bullet/detector/base.rb +2 -1
  21. data/lib/bullet/detector/counter_cache.rb +2 -2
  22. data/lib/bullet/detector/n_plus_one_query.rb +24 -13
  23. data/lib/bullet/detector/unused_eager_loading.rb +3 -3
  24. data/lib/bullet/mongoid4x.rb +1 -1
  25. data/lib/bullet/mongoid5x.rb +1 -1
  26. data/lib/bullet/mongoid6x.rb +1 -1
  27. data/lib/bullet/mongoid7x.rb +32 -17
  28. data/lib/bullet/notification.rb +2 -1
  29. data/lib/bullet/rack.rb +64 -23
  30. data/lib/bullet/registry/call_stack.rb +12 -0
  31. data/lib/bullet/registry.rb +1 -0
  32. data/lib/bullet/stack_trace_filter.rb +15 -15
  33. data/lib/bullet/version.rb +1 -1
  34. data/lib/bullet.rb +35 -29
  35. data/lib/generators/bullet/install_generator.rb +22 -25
  36. data/perf/benchmark.rb +4 -1
  37. data/spec/bullet/detector/counter_cache_spec.rb +1 -1
  38. data/spec/bullet/detector/n_plus_one_query_spec.rb +1 -33
  39. data/spec/bullet/detector/unused_eager_loading_spec.rb +15 -10
  40. data/spec/bullet/ext/object_spec.rb +1 -1
  41. data/spec/bullet/notification/base_spec.rb +4 -4
  42. data/spec/bullet/notification/n_plus_one_query_spec.rb +1 -3
  43. data/spec/bullet/rack_spec.rb +152 -9
  44. data/spec/bullet/stack_trace_filter_spec.rb +26 -0
  45. data/spec/bullet_spec.rb +15 -15
  46. data/spec/integration/active_record/association_spec.rb +95 -12
  47. data/spec/integration/counter_cache_spec.rb +4 -4
  48. data/spec/integration/mongoid/association_spec.rb +4 -4
  49. data/spec/models/attachment.rb +5 -0
  50. data/spec/models/deal.rb +5 -0
  51. data/spec/models/folder.rb +2 -1
  52. data/spec/models/group.rb +2 -1
  53. data/spec/models/page.rb +2 -1
  54. data/spec/models/post.rb +2 -0
  55. data/spec/models/role.rb +7 -0
  56. data/spec/models/submission.rb +1 -0
  57. data/spec/models/user.rb +2 -0
  58. data/spec/models/writer.rb +2 -1
  59. data/spec/spec_helper.rb +0 -2
  60. data/spec/support/mongo_seed.rb +1 -0
  61. data/spec/support/sqlite_seed.rb +38 -0
  62. data/test.sh +2 -0
  63. metadata +20 -7
  64. data/.travis.yml +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd668fdfd675ea8437eee0242974d7cb1cfacc0479be4cc5f3f58ee7d05a6d63
4
- data.tar.gz: 3d841fb8471fe18b66135fa087ee3d1874f412c114d09ba05ba150e2daaf9775
3
+ metadata.gz: 0f47e147f5df074217ee7a65123f54a1918f98bde162c7d4bf1f76bffc9f15a6
4
+ data.tar.gz: e05e48b96a5e68bfbcac63f4dce4601d717ec1a32ee83a5c45aad738e1bfc48b
5
5
  SHA512:
6
- metadata.gz: 714c614f2cf44f332f4f9996638c10dca565c92a2279316509256fefba2ca824fc9c71d2a3c3e4ca28edfc45849f76b61e521158e0051c365f5b8a81f41e9d8d
7
- data.tar.gz: a3b1a7e58b6e5554a641aa4b8edf16dbb4983b2f7a072c5b7275ee04a7251e4d095fed37f82d2945ef759603c8aeaf8a394d9e7fcf9f70a723e6235ab5f3e646
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
@@ -2,7 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '6.0.0'
5
+ gem 'rails', '~> 6.0.0'
6
6
  gem 'sqlite3'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
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
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 7.0.0'
6
+ gem 'sqlite3'
7
+ gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
+ gem 'activerecord-import'
9
+
10
+ gem "rspec"
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 - 2010 Richard Huang (flyerhzm@gmail.com)
1
+ Copyright (c) 2009 - 2022 Richard Huang (flyerhzm@gmail.com)
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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 do ANYTHING unless you tell it to explicitly. Append to
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 XHR into the returned HTML. This must be false for receiving alerts or console logging.
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
- ## Whitelist
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 whitelist these to ignore them:
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.add_whitelist :type => :n_plus_one_query, :class_name => "Post", :association => :comments
121
- Bullet.add_whitelist :type => :unused_eager_loading, :class_name => "Post", :association => :comments
122
- Bullet.add_whitelist :type => :counter_cache, :class_name => "Country", :association => :cities
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] N+1 Query: PATH_INFO: /posts; model: Post => associations: [comments]·
150
- Add to your finder: :include => [:comments]
151
- 2009-08-25 20:40:17[INFO] N+1 Query: method call stack:·
152
- /Users/richard/Downloads/test/app/views/posts/index.html.erb:11:in `_run_erb_app47views47posts47index46html46erb'
153
- /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `each'
154
- /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `_run_erb_app47views47posts47index46html46erb'
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 two lines are notifications that N+1 queries have been encountered. The remaining lines are stack traces so you can find exactly where the queries were invoked in your code, and fix them.
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] Unused eager loadings: PATH_INFO: /posts; model: Post => associations: [comments]·
164
- Remove from your finder: :include => [:comments]
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 two lines are notifications that unused eager loadings have been encountered.
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
- ## Growl, XMPP/Jabber and Airbrake Support
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 visit [https://github.com/flyerhzm/bullet_test](https://github.com/flyerhzm/bullet_test) or
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/model/post.rb` and `app/model/comment.rb`
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 - 2019 Richard Huang (flyerhzm@gmail.com), released under the MIT license
489
+ Copyright (c) 2009 - 2022 Richard Huang (flyerhzm@gmail.com), released under the MIT license
@@ -3,7 +3,11 @@
3
3
  module Bullet
4
4
  module ActiveJob
5
5
  def self.included(base)
6
- base.class_eval { around_perform { |_job, block| Bullet.profile { block.call } } }
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
- Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
181
- association = owner.association refl.name
182
- Array(association.target).each do |through_record|
183
- Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
184
- end
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
- if refl.through_reflection?
187
- refl = refl.through_reflection while refl.through_reflection?
187
+ if refl.through_reflection?
188
+ refl = refl.through_reflection while refl.through_reflection?
188
189
 
189
- Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
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
- Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
160
- association = owner.association reflection.through_reflection.name
161
- Array(association.target).each do |through_record|
162
- Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
163
- end
164
-
165
- if reflection.through_reflection != through_reflection
166
- Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
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
- Array(association.target).each do |through_record|
189
- Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
190
- end
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
- if reflection.through_reflection != through_reflection
193
- Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
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)