bullet 6.1.3 → 7.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +82 -0
  3. data/CHANGELOG.md +36 -0
  4. data/Gemfile.rails-7.0 +10 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +31 -26
  7. data/lib/bullet/active_record41.rb +1 -0
  8. data/lib/bullet/active_record42.rb +1 -0
  9. data/lib/bullet/active_record5.rb +6 -4
  10. data/lib/bullet/active_record52.rb +18 -22
  11. data/lib/bullet/active_record60.rb +17 -21
  12. data/lib/bullet/active_record61.rb +17 -21
  13. data/lib/bullet/active_record70.rb +277 -0
  14. data/lib/bullet/bullet_xhr.js +3 -2
  15. data/lib/bullet/dependency.rb +10 -0
  16. data/lib/bullet/detector/base.rb +2 -1
  17. data/lib/bullet/detector/counter_cache.rb +2 -2
  18. data/lib/bullet/detector/n_plus_one_query.rb +5 -5
  19. data/lib/bullet/detector/unused_eager_loading.rb +2 -2
  20. data/lib/bullet/mongoid7x.rb +34 -19
  21. data/lib/bullet/notification.rb +2 -1
  22. data/lib/bullet/rack.rb +7 -4
  23. data/lib/bullet/stack_trace_filter.rb +7 -8
  24. data/lib/bullet/version.rb +1 -1
  25. data/lib/bullet.rb +23 -24
  26. data/lib/generators/bullet/install_generator.rb +0 -1
  27. data/perf/benchmark.rb +4 -1
  28. data/spec/bullet/detector/n_plus_one_query_spec.rb +1 -1
  29. data/spec/bullet/detector/unused_eager_loading_spec.rb +6 -2
  30. data/spec/bullet/ext/object_spec.rb +1 -1
  31. data/spec/bullet/notification/base_spec.rb +4 -4
  32. data/spec/bullet/rack_spec.rb +90 -19
  33. data/spec/bullet_spec.rb +15 -15
  34. data/spec/integration/active_record/association_spec.rb +36 -9
  35. data/spec/integration/counter_cache_spec.rb +4 -4
  36. data/spec/integration/mongoid/association_spec.rb +1 -1
  37. data/spec/models/deal.rb +5 -0
  38. data/spec/models/folder.rb +2 -1
  39. data/spec/models/group.rb +2 -1
  40. data/spec/models/page.rb +2 -1
  41. data/spec/models/post.rb +2 -0
  42. data/spec/models/role.rb +7 -0
  43. data/spec/models/user.rb +1 -0
  44. data/spec/models/writer.rb +2 -1
  45. data/spec/spec_helper.rb +0 -2
  46. data/spec/support/mongo_seed.rb +1 -0
  47. data/spec/support/sqlite_seed.rb +30 -0
  48. data/test.sh +2 -0
  49. metadata +10 -4
  50. data/.travis.yml +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b574ae38dafed75dc9aded2d6c97ab057593fcda5a49ec4875bc327f99625efd
4
- data.tar.gz: df882c895e98b91a26371b670ffd439a2a39e80df57ce1b61a87de6e89c10c1a
3
+ metadata.gz: 1ee8344236feb882d0359202c851abb8887b6b3bb31186f2b37329a41fbc3e96
4
+ data.tar.gz: 9d1aea1b67a6777c56b2548e93614ee051d5799e8caf9ecb0d48663a6a7b5bd8
5
5
  SHA512:
6
- metadata.gz: 475691616eca228e0938effbc8a9a8930d8ab33f673d4cb2a75ff02b2933ba01ee2a570fff1d9d669700fb05cf09dff9149555f1f2b35c4a31c8904620db70e3
7
- data.tar.gz: 86f37317790084aa7ca3860c1757a41354678a1a0bfbf56fe6f21ebe6793eef5ff257fe75bbad77b999484a9e1abb527d9e9ac877dda04cf9f1236e110e6d561
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,41 @@
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
+
3
39
  ## 6.1.3 (01/21/2021)
4
40
 
5
41
  * Consider ThroughAssociation at SingularAssociation like CollectionAssociation
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
 
@@ -49,7 +49,7 @@ mongoid.
49
49
 
50
50
  ## Configuration
51
51
 
52
- 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
53
53
  `config/environments/development.rb` initializer with the following code:
54
54
 
55
55
  ```ruby
@@ -59,7 +59,6 @@ config.after_initialize do
59
59
  Bullet.alert = true
60
60
  Bullet.bullet_logger = true
61
61
  Bullet.console = true
62
- Bullet.growl = true
63
62
  Bullet.xmpp = { :account => 'bullets_account@jabber.org',
64
63
  :password => 'bullets_password_for_jabber',
65
64
  :receiver => 'your_account@jabber.org',
@@ -67,6 +66,7 @@ config.after_initialize do
67
66
  Bullet.rails_logger = true
68
67
  Bullet.honeybadger = true
69
68
  Bullet.bugsnag = true
69
+ Bullet.appsignal = true
70
70
  Bullet.airbrake = true
71
71
  Bullet.rollbar = true
72
72
  Bullet.add_footer = true
@@ -84,16 +84,17 @@ The code above will enable all of the Bullet notification systems:
84
84
  * `Bullet.alert`: pop up a JavaScript alert in the browser
85
85
  * `Bullet.bullet_logger`: log to the Bullet log file (Rails.root/log/bullet.log)
86
86
  * `Bullet.console`: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
87
- * `Bullet.growl`: pop up Growl warnings if your system has Growl installed. Requires a little bit of configuration
88
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.
89
88
  * `Bullet.rails_logger`: add warnings directly to the Rails log
90
89
  * `Bullet.honeybadger`: add notifications to Honeybadger
91
90
  * `Bullet.bugsnag`: add notifications to bugsnag
92
91
  * `Bullet.airbrake`: add notifications to airbrake
92
+ * `Bullet.appsignal`: add notifications to AppSignal
93
93
  * `Bullet.rollbar`: add notifications to rollbar
94
94
  * `Bullet.sentry`: add notifications to sentry
95
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.
96
- * `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.
97
98
  * `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
98
99
  * `Bullet.stacktrace_excludes`: ignore paths with any of these substrings in the stack trace, even if they are not in your main app.
99
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
@@ -118,15 +119,15 @@ Bullet.unused_eager_loading_enable = false
118
119
  Bullet.counter_cache_enable = false
119
120
  ```
120
121
 
121
- ## Whitelist
122
+ ## Safe list
122
123
 
123
124
  Sometimes Bullet may notify you of query problems you don't care to fix, or
124
- 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:
125
126
 
126
127
  ```ruby
127
- Bullet.add_whitelist :type => :n_plus_one_query, :class_name => "Post", :association => :comments
128
- Bullet.add_whitelist :type => :unused_eager_loading, :class_name => "Post", :association => :comments
129
- 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
130
131
  ```
131
132
 
132
133
  If you want to skip bullet in some specific controller actions, you can
@@ -153,25 +154,26 @@ The Bullet log `log/bullet.log` will look something like this:
153
154
  * N+1 Query:
154
155
 
155
156
  ```
156
- 2009-08-25 20:40:17[INFO] N+1 Query: PATH_INFO: /posts; model: Post => associations: [comments]·
157
- Add to your finder: :include => [:comments]
158
- 2009-08-25 20:40:17[INFO] N+1 Query: method call stack:·
159
- /Users/richard/Downloads/test/app/views/posts/index.html.erb:11:in `_run_erb_app47views47posts47index46html46erb'
160
- /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `each'
161
- /Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `_run_erb_app47views47posts47index46html46erb'
162
- /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'
163
163
  ```
164
164
 
165
- 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.
166
166
 
167
167
  * Unused eager loading:
168
168
 
169
169
  ```
170
- 2009-08-25 20:53:56[INFO] Unused eager loadings: PATH_INFO: /posts; model: Post => associations: [comments]·
171
- 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
172
174
  ```
173
175
 
174
- These two lines are notifications that unused eager loadings have been encountered.
176
+ These lines are notifications that unused eager loadings have been encountered.
175
177
 
176
178
  * Need counter cache:
177
179
 
@@ -180,10 +182,14 @@ These two lines are notifications that unused eager loadings have been encounter
180
182
  Post => [:comments]
181
183
  ```
182
184
 
183
- ## Growl, XMPP/Jabber and Airbrake Support
185
+ ## XMPP/Jabber and Airbrake Support
184
186
 
185
187
  see [https://github.com/flyerhzm/uniform_notifier](https://github.com/flyerhzm/uniform_notifier)
186
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
+
187
193
  ## Important
188
194
 
189
195
  If you find Bullet does not work for you, *please disable your browser's cache*.
@@ -267,8 +273,7 @@ Bullet outputs some details info, to enable debug mode, set
267
273
  ## Demo
268
274
 
269
275
  Bullet is designed to function as you browse through your application in development. To see it in action,
270
- you can visit [https://github.com/flyerhzm/bullet_test](https://github.com/flyerhzm/bullet_test) or
271
- 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.
272
277
 
273
278
  1\. Create an example application
274
279
 
@@ -280,7 +285,7 @@ $ rails g scaffold comment name:string post_id:integer
280
285
  $ bundle exec rake db:migrate
281
286
  ```
282
287
 
283
- 2\. Change `app/model/post.rb` and `app/model/comment.rb`
288
+ 2\. Change `app/models/post.rb` and `app/models/comment.rb`
284
289
 
285
290
  ```ruby
286
291
  class Post < ActiveRecord::Base
@@ -479,4 +484,4 @@ Meanwhile, there's a line appended to `log/bullet.log`
479
484
  Post => [:comments]
480
485
  ```
481
486
 
482
- 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
@@ -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
@@ -205,7 +201,7 @@ module Bullet
205
201
  if is_a? ::ActiveRecord::Associations::ThroughAssociation
206
202
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
207
203
  association = owner.association reflection.through_reflection.name
208
- Array(association.target).each do |through_record|
204
+ Array.wrap(association.target).each do |through_record|
209
205
  Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
210
206
  end
211
207
 
@@ -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
@@ -232,7 +228,7 @@ module Bullet
232
228
  if is_a? ::ActiveRecord::Associations::ThroughAssociation
233
229
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
234
230
  association = owner.association(reflection.through_reflection.name)
235
- Array(association.target).each do |through_record|
231
+ Array.wrap(association.target).each do |through_record|
236
232
  Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
237
233
  end
238
234
 
@@ -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
@@ -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
@@ -232,7 +228,7 @@ module Bullet
232
228
  if is_a? ::ActiveRecord::Associations::ThroughAssociation
233
229
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
234
230
  association = owner.association(reflection.through_reflection.name)
235
- Array(association.target).each do |through_record|
231
+ Array.wrap(association.target).each do |through_record|
236
232
  Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
237
233
  end
238
234