bullet 6.1.0 → 7.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +82 -0
  3. data/CHANGELOG.md +50 -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 +38 -26
  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 +6 -4
  13. data/lib/bullet/active_record52.rb +28 -21
  14. data/lib/bullet/active_record60.rb +27 -20
  15. data/lib/bullet/active_record61.rb +274 -0
  16. data/lib/bullet/active_record70.rb +277 -0
  17. data/lib/bullet/bullet_xhr.js +18 -17
  18. data/lib/bullet/dependency.rb +16 -0
  19. data/lib/bullet/detector/base.rb +2 -1
  20. data/lib/bullet/detector/counter_cache.rb +2 -2
  21. data/lib/bullet/detector/n_plus_one_query.rb +5 -5
  22. data/lib/bullet/detector/unused_eager_loading.rb +2 -2
  23. data/lib/bullet/mongoid4x.rb +1 -1
  24. data/lib/bullet/mongoid5x.rb +1 -1
  25. data/lib/bullet/mongoid6x.rb +1 -1
  26. data/lib/bullet/mongoid7x.rb +32 -17
  27. data/lib/bullet/notification.rb +2 -1
  28. data/lib/bullet/rack.rb +28 -19
  29. data/lib/bullet/stack_trace_filter.rb +7 -9
  30. data/lib/bullet/version.rb +1 -1
  31. data/lib/bullet.rb +29 -28
  32. data/lib/generators/bullet/install_generator.rb +22 -25
  33. data/perf/benchmark.rb +4 -1
  34. data/spec/bullet/detector/counter_cache_spec.rb +1 -1
  35. data/spec/bullet/detector/n_plus_one_query_spec.rb +1 -1
  36. data/spec/bullet/detector/unused_eager_loading_spec.rb +10 -10
  37. data/spec/bullet/ext/object_spec.rb +1 -1
  38. data/spec/bullet/notification/base_spec.rb +4 -4
  39. data/spec/bullet/notification/n_plus_one_query_spec.rb +1 -3
  40. data/spec/bullet/rack_spec.rb +135 -9
  41. data/spec/bullet_spec.rb +15 -15
  42. data/spec/integration/active_record/association_spec.rb +73 -11
  43. data/spec/integration/counter_cache_spec.rb +4 -4
  44. data/spec/integration/mongoid/association_spec.rb +4 -4
  45. data/spec/models/attachment.rb +5 -0
  46. data/spec/models/deal.rb +5 -0
  47. data/spec/models/folder.rb +2 -1
  48. data/spec/models/group.rb +2 -1
  49. data/spec/models/page.rb +2 -1
  50. data/spec/models/post.rb +2 -0
  51. data/spec/models/role.rb +7 -0
  52. data/spec/models/submission.rb +1 -0
  53. data/spec/models/user.rb +2 -0
  54. data/spec/models/writer.rb +2 -1
  55. data/spec/spec_helper.rb +0 -2
  56. data/spec/support/mongo_seed.rb +1 -0
  57. data/spec/support/sqlite_seed.rb +38 -0
  58. data/test.sh +2 -0
  59. metadata +17 -7
  60. 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: 1ee8344236feb882d0359202c851abb8887b6b3bb31186f2b37329a41fbc3e96
4
+ data.tar.gz: 9d1aea1b67a6777c56b2548e93614ee051d5799e8caf9ecb0d48663a6a7b5bd8
5
5
  SHA512:
6
- metadata.gz: 714c614f2cf44f332f4f9996638c10dca565c92a2279316509256fefba2ca824fc9c71d2a3c3e4ca28edfc45849f76b61e521158e0051c365f5b8a81f41e9d8d
7
- data.tar.gz: a3b1a7e58b6e5554a641aa4b8edf16dbb4983b2f7a072c5b7275ee04a7251e4d095fed37f82d2945ef759603c8aeaf8a394d9e7fcf9f70a723e6235ab5f3e646
6
+ metadata.gz: f603fb2540b20dd0e5d5e519de308b9a264d264bbea6db9d7399c25d6912e053aa243cb877b98cfa123f3eca9142bc0fec1bf9b4ff41f411efd6a895f616916b
7
+ data.tar.gz: 1e000b7bb96d2479108bb67bc6ac6d4efdc3f337f76f42e8227d1b8b9394a7d38d09df0104ceb3ed7b6e9a98b570dc0f32d3eeff85277490e4ee0c552b577f5b
@@ -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,55 @@
1
1
  ## Next Release
2
2
 
3
+ ## 7.0.4 (11/28/2022)
4
+
5
+ * Fix `eager_load` `has_many :through` false positives
6
+ * mongoid7x: add dynamic methods
7
+
8
+ ## 7.0.3 (08/13/2022)
9
+
10
+ * Replace `Array()` with `Array.wrap()`
11
+
12
+ ## 7.0.2 (05/31/2022)
13
+
14
+ * Drop growl support
15
+ * Do not check html tag in Bullet::Rack anymore
16
+
17
+ ## 7.0.1 (01/15/2022)
18
+
19
+ * Get rid of *_whitelist methods
20
+ * Hack ActiveRecord::Associations::Preloader::Batch in rails 7
21
+
22
+ ## 7.0.0 (12/18/2021)
23
+
24
+ * Support rails 7
25
+ * Fix Mongoid 7 view iteration
26
+ * Move CI from Travis to Github Actions
27
+
28
+ ## 6.1.5 (08/16/2021)
29
+
30
+ * Rename whitelist to safelist
31
+ * Fix onload called twice
32
+ * Support Rack::Files::Iterator responses
33
+ * Ensure HABTM associations are not incorrectly labeled n+1
34
+
35
+ ## 6.1.4 (02/26/2021)
36
+
37
+ * Added an option to stop adding HTTP headers to API requests
38
+
39
+ ## 6.1.3 (01/21/2021)
40
+
41
+ * Consider ThroughAssociation at SingularAssociation like CollectionAssociation
42
+ * Add xhr_script only when add_footer is enabled
43
+
44
+ ## 6.1.2 (12/12/2020)
45
+
46
+ * Revert "Make whitelist thread safe"
47
+
48
+ ## 6.1.1 (12/12/2020)
49
+
50
+ * Add support Rails 6.1
51
+ * Make whitelist thread safe
52
+
3
53
  ## 6.1.0 (12/28/2019)
4
54
 
5
55
  * 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*.
@@ -260,8 +273,7 @@ Bullet outputs some details info, to enable debug mode, set
260
273
  ## Demo
261
274
 
262
275
  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.
276
+ you can follow these steps to create, detect, and fix example query problems.
265
277
 
266
278
  1\. Create an example application
267
279
 
@@ -273,7 +285,7 @@ $ rails g scaffold comment name:string post_id:integer
273
285
  $ bundle exec rake db:migrate
274
286
  ```
275
287
 
276
- 2\. Change `app/model/post.rb` and `app/model/comment.rb`
288
+ 2\. Change `app/models/post.rb` and `app/models/comment.rb`
277
289
 
278
290
  ```ruby
279
291
  class Post < ActiveRecord::Base
@@ -472,4 +484,4 @@ Meanwhile, there's a line appended to `log/bullet.log`
472
484
  Post => [:comments]
473
485
  ```
474
486
 
475
- Copyright (c) 2009 - 2019 Richard Huang (flyerhzm@gmail.com), released under the MIT license
487
+ 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,10 +177,12 @@ 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)
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
184
186
  end
185
187
 
186
188
  if refl.through_reflection?
@@ -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,10 +150,12 @@ 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)
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
163
159
  end
164
160
 
165
161
  if reflection.through_reflection != through_reflection
@@ -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,10 +177,12 @@ 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)
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
190
186
  end
191
187
 
192
188
  if reflection.through_reflection != through_reflection
@@ -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)