bullet 5.7.4 → 5.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -11
- data/Gemfile.rails-5.2 +1 -1
- data/README.md +7 -4
- data/Rakefile +1 -1
- data/bullet.gemspec +9 -3
- data/lib/bullet/active_record4.rb +15 -13
- data/lib/bullet/active_record41.rb +15 -13
- data/lib/bullet/active_record42.rb +16 -13
- data/lib/bullet/active_record5.rb +26 -13
- data/lib/bullet/active_record52.rb +21 -13
- data/lib/bullet/dependency.rb +3 -1
- data/lib/bullet/detector/association.rb +4 -2
- data/lib/bullet/detector/base.rb +2 -0
- data/lib/bullet/detector/counter_cache.rb +3 -0
- data/lib/bullet/detector/n_plus_one_query.rb +11 -9
- data/lib/bullet/detector/unused_eager_loading.rb +3 -0
- data/lib/bullet/detector.rb +2 -0
- data/lib/bullet/ext/object.rb +3 -1
- data/lib/bullet/ext/string.rb +3 -1
- data/lib/bullet/mongoid4x.rb +7 -2
- data/lib/bullet/mongoid5x.rb +7 -2
- data/lib/bullet/mongoid6x.rb +7 -4
- data/lib/bullet/notification/base.rb +3 -1
- data/lib/bullet/notification/counter_cache.rb +2 -0
- data/lib/bullet/notification/n_plus_one_query.rb +2 -0
- data/lib/bullet/notification/unused_eager_loading.rb +2 -0
- data/lib/bullet/notification.rb +2 -0
- data/lib/bullet/notification_collector.rb +2 -0
- data/lib/bullet/rack.rb +19 -15
- data/lib/bullet/registry/association.rb +2 -0
- data/lib/bullet/registry/base.rb +2 -0
- data/lib/bullet/registry/object.rb +2 -0
- data/lib/bullet/registry.rb +2 -0
- data/lib/bullet/stack_trace_filter.rb +43 -22
- data/lib/bullet/version.rb +3 -1
- data/lib/bullet.rb +5 -2
- data/lib/generators/bullet/install_generator.rb +5 -3
- data/perf/benchmark.rb +2 -0
- data/rails/init.rb +2 -0
- data/spec/bullet/detector/association_spec.rb +2 -0
- data/spec/bullet/detector/base_spec.rb +2 -0
- data/spec/bullet/detector/counter_cache_spec.rb +2 -0
- data/spec/bullet/detector/n_plus_one_query_spec.rb +25 -0
- data/spec/bullet/detector/unused_eager_loading_spec.rb +2 -0
- data/spec/bullet/ext/object_spec.rb +2 -0
- data/spec/bullet/ext/string_spec.rb +2 -0
- data/spec/bullet/notification/base_spec.rb +2 -0
- data/spec/bullet/notification/counter_cache_spec.rb +2 -0
- data/spec/bullet/notification/n_plus_one_query_spec.rb +2 -0
- data/spec/bullet/notification/unused_eager_loading_spec.rb +2 -0
- data/spec/bullet/notification_collector_spec.rb +2 -0
- data/spec/bullet/rack_spec.rb +2 -0
- data/spec/bullet/registry/association_spec.rb +2 -0
- data/spec/bullet/registry/base_spec.rb +2 -0
- data/spec/bullet/registry/object_spec.rb +2 -0
- data/spec/bullet_spec.rb +2 -0
- data/spec/integration/active_record/association_spec.rb +63 -1
- data/spec/integration/counter_cache_spec.rb +2 -0
- data/spec/integration/mongoid/association_spec.rb +2 -0
- data/spec/models/address.rb +2 -0
- data/spec/models/author.rb +2 -0
- data/spec/models/base_user.rb +2 -0
- data/spec/models/category.rb +2 -0
- data/spec/models/city.rb +2 -0
- data/spec/models/client.rb +4 -0
- data/spec/models/comment.rb +2 -0
- data/spec/models/company.rb +2 -0
- data/spec/models/country.rb +2 -0
- data/spec/models/document.rb +2 -0
- data/spec/models/entry.rb +2 -0
- data/spec/models/firm.rb +3 -0
- data/spec/models/folder.rb +2 -0
- data/spec/models/group.rb +4 -0
- data/spec/models/mongoid/address.rb +2 -0
- data/spec/models/mongoid/category.rb +2 -0
- data/spec/models/mongoid/comment.rb +2 -0
- data/spec/models/mongoid/company.rb +2 -0
- data/spec/models/mongoid/entry.rb +2 -0
- data/spec/models/mongoid/post.rb +2 -0
- data/spec/models/mongoid/user.rb +2 -0
- data/spec/models/newspaper.rb +2 -0
- data/spec/models/page.rb +2 -0
- data/spec/models/person.rb +2 -0
- data/spec/models/pet.rb +2 -0
- data/spec/models/post.rb +17 -0
- data/spec/models/relationship.rb +2 -0
- data/spec/models/reply.rb +2 -0
- data/spec/models/student.rb +2 -0
- data/spec/models/submission.rb +2 -0
- data/spec/models/teacher.rb +2 -0
- data/spec/models/user.rb +2 -0
- data/spec/models/writer.rb +2 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/bullet_ext.rb +2 -0
- data/spec/support/mongo_seed.rb +4 -2
- data/spec/support/rack_double.rb +2 -0
- data/spec/support/sqlite_seed.rb +13 -4
- data/tasks/bullet_tasks.rake +2 -0
- metadata +9 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0b65855ae5365567a18d1fb6ffdee5046b8cec35
|
|
4
|
+
data.tar.gz: 8df6b7afd18400dd2fe9bf39ec4a537fa04228af
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 212cf02f1520dfaf752f794e42e9b2611fa0eca8b786bf5ef281c36c416ddf24016a524029614447c6241ebb734a2491ab554fa505544d7a7bc6f2e5b767527d
|
|
7
|
+
data.tar.gz: d2d71ceb54033f58cb6d675ea88268f130a0ea8bcfd7b4987486e374a2d2a3fc9169691ff20a9ca0fd9cf2787656dacc19649a8473879e9d1d68484597ccc18b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
## Next Release
|
|
2
2
|
|
|
3
|
-
## 5.
|
|
3
|
+
## 5.8.0 (10/29/2018)
|
|
4
4
|
|
|
5
|
+
* Fix through reflection for rails 5.x
|
|
6
|
+
* Fix false positive in after_save/after_create callbacks
|
|
7
|
+
* Don't triger a preload error on "manual" preloads
|
|
5
8
|
* Avoid Bullet from making extra queries in mongoid6
|
|
9
|
+
* Support option for #first and #last on mongoid6.x
|
|
10
|
+
* Fix duplicate logs in mongoid 4.x and 5.x version
|
|
6
11
|
* Use caller for ruby 1.9 while caller_locations for 2.0+
|
|
7
|
-
|
|
8
|
-
## 5.7.3 (17/02/2018)
|
|
9
|
-
|
|
12
|
+
* Extend stacktrace matching for sub-file precision
|
|
10
13
|
* Exclude configured bundler path in addition to '/vendor'
|
|
11
|
-
* Support rails 5.1.5
|
|
12
|
-
|
|
13
|
-
## 5.7.2 (18/01/2018)
|
|
14
|
-
|
|
15
14
|
* Fix `caller_path` in `excluded_stacktrace_path`
|
|
16
|
-
|
|
17
|
-
## 5.7.1 (07/01/2017)
|
|
18
|
-
|
|
19
15
|
* Update `uniform_notifier` dependency to add Sentry support
|
|
16
|
+
* Integrate awesomecode.io and refactor code
|
|
20
17
|
|
|
21
18
|
## 5.7.0 (12/03/2017)
|
|
22
19
|
|
data/Gemfile.rails-5.2
CHANGED
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](http://badge.fury.io/rb/bullet)
|
|
4
4
|
[](http://travis-ci.org/flyerhzm/bullet)
|
|
5
|
-
[](https://awesomecode.io/
|
|
5
|
+
[](https://awesomecode.io/repos/flyerhzm/bullet)
|
|
6
6
|
[](http://coderwall.com/flyerhzm)
|
|
7
7
|
|
|
8
8
|
The Bullet gem is designed to help you increase your application's performance by reducing the number of queries it makes. It will watch your queries while you develop your application and notify you when you should add eager loading (N+1 queries), when you're using eager loading that isn't necessary and when you should use counter cache.
|
|
@@ -64,7 +64,7 @@ config.after_initialize do
|
|
|
64
64
|
Bullet.rollbar = true
|
|
65
65
|
Bullet.add_footer = true
|
|
66
66
|
Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
|
|
67
|
-
Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware' ]
|
|
67
|
+
Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware', ['my_file.rb', 'my_method'], ['my_file.rb', 16..20] ]
|
|
68
68
|
Bullet.slack = { webhook_url: 'http://some.slack.url', channel: '#default', username: 'notifier' }
|
|
69
69
|
end
|
|
70
70
|
```
|
|
@@ -87,6 +87,8 @@ The code above will enable all of the Bullet notification systems:
|
|
|
87
87
|
* `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.
|
|
88
88
|
* `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
|
|
89
89
|
* `Bullet.stacktrace_excludes`: ignore paths with any of these substrings in the stack trace, even if they are not in your main app.
|
|
90
|
+
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
|
|
91
|
+
item is a line number, a Range of line numbers, or a (bare) method name, to exclude only particular lines in a file.
|
|
90
92
|
* `Bullet.slack`: add notifications to slack
|
|
91
93
|
* `Bullet.raise`: raise errors, useful for making your specs fail unless they have optimized queries
|
|
92
94
|
|
|
@@ -126,10 +128,11 @@ class ApplicationController < ActionController::Base
|
|
|
126
128
|
around_action :skip_bullet
|
|
127
129
|
|
|
128
130
|
def skip_bullet
|
|
131
|
+
previous_value = Bullet.enable?
|
|
129
132
|
Bullet.enable = false
|
|
130
133
|
yield
|
|
131
134
|
ensure
|
|
132
|
-
Bullet.enable =
|
|
135
|
+
Bullet.enable = previous_value
|
|
133
136
|
end
|
|
134
137
|
end
|
|
135
138
|
```
|
|
@@ -180,7 +183,7 @@ If you find Bullet does not work for you, *please disable your browser's cache*.
|
|
|
180
183
|
|
|
181
184
|
### Profile a job
|
|
182
185
|
|
|
183
|
-
The Bullet gem uses rack middleware to profile requests. If you want to use Bullet without an http server, like to profile a job, you can use
|
|
186
|
+
The Bullet gem uses rack middleware to profile requests. If you want to use Bullet without an http server, like to profile a job, you can use the profile method and fetch warnings
|
|
184
187
|
|
|
185
188
|
```ruby
|
|
186
189
|
Bullet.profile do
|
data/Rakefile
CHANGED
data/bullet.gemspec
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
2
4
|
$LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
|
|
3
5
|
|
|
4
6
|
require 'bullet/version'
|
|
@@ -12,13 +14,17 @@ Gem::Specification.new do |s|
|
|
|
12
14
|
s.homepage = 'https://github.com/flyerhzm/bullet'
|
|
13
15
|
s.summary = 'help to kill N+1 queries and unused eager loading.'
|
|
14
16
|
s.description = 'help to kill N+1 queries and unused eager loading.'
|
|
17
|
+
s.metadata = {
|
|
18
|
+
'changelog_uri' => 'https://github.com/flyerhzm/bullet/blob/master/CHANGELOG.md',
|
|
19
|
+
'source_code_uri' => 'https://github.com/flyerhzm/bullet'
|
|
20
|
+
}
|
|
15
21
|
|
|
16
|
-
s.license
|
|
22
|
+
s.license = 'MIT'
|
|
17
23
|
|
|
18
24
|
s.required_rubygems_version = '>= 1.3.6'
|
|
19
25
|
|
|
20
26
|
s.add_runtime_dependency 'activesupport', '>= 3.0.0'
|
|
21
|
-
s.add_runtime_dependency 'uniform_notifier', '~> 1.11
|
|
27
|
+
s.add_runtime_dependency 'uniform_notifier', '~> 1.11'
|
|
22
28
|
|
|
23
29
|
s.files = `git ls-files`.split("\n")
|
|
24
30
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module ActiveRecord
|
|
3
5
|
def self.enable
|
|
@@ -46,21 +48,12 @@ module Bullet
|
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
::ActiveRecord::Persistence.class_eval do
|
|
49
|
-
def
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
alias_method_chain :save, :bullet
|
|
56
|
-
|
|
57
|
-
def save_with_bullet!(*args, &proc)
|
|
58
|
-
was_new_record = new_record?
|
|
59
|
-
save_without_bullet!(*args, &proc).tap do |result|
|
|
60
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
51
|
+
def _create_record_with_bullet(*args)
|
|
52
|
+
_create_record_without_bullet(*args).tap do
|
|
53
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
|
61
54
|
end
|
|
62
55
|
end
|
|
63
|
-
alias_method_chain :
|
|
56
|
+
alias_method_chain :_create_record, :bullet
|
|
64
57
|
end
|
|
65
58
|
|
|
66
59
|
::ActiveRecord::Associations::Preloader.class_eval do
|
|
@@ -72,6 +65,7 @@ module Bullet
|
|
|
72
65
|
if Bullet.start?
|
|
73
66
|
records = [records].flatten.compact.uniq
|
|
74
67
|
return if records.empty?
|
|
68
|
+
|
|
75
69
|
records.each do |record|
|
|
76
70
|
Bullet::Detector::Association.add_object_associations(record, associations)
|
|
77
71
|
end
|
|
@@ -197,6 +191,14 @@ module Bullet
|
|
|
197
191
|
end
|
|
198
192
|
# rubocop:enable Style/MethodCallWithoutArgsParentheses
|
|
199
193
|
end
|
|
194
|
+
|
|
195
|
+
::ActiveRecord::Associations::BelongsToAssociation.class_eval do
|
|
196
|
+
def writer_with_bullet(record)
|
|
197
|
+
Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
|
|
198
|
+
writer_without_bullet(record)
|
|
199
|
+
end
|
|
200
|
+
alias_method_chain :writer, :bullet
|
|
201
|
+
end
|
|
200
202
|
end
|
|
201
203
|
end
|
|
202
204
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module ActiveRecord
|
|
3
5
|
def self.enable
|
|
@@ -48,21 +50,12 @@ module Bullet
|
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
::ActiveRecord::Persistence.class_eval do
|
|
51
|
-
def
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
alias_method_chain :save, :bullet
|
|
58
|
-
|
|
59
|
-
def save_with_bullet!(*args, &proc)
|
|
60
|
-
was_new_record = new_record?
|
|
61
|
-
save_without_bullet!(*args, &proc).tap do |result|
|
|
62
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
53
|
+
def _create_record_with_bullet(*args)
|
|
54
|
+
_create_record_without_bullet(*args).tap do
|
|
55
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
|
63
56
|
end
|
|
64
57
|
end
|
|
65
|
-
alias_method_chain :
|
|
58
|
+
alias_method_chain :_create_record, :bullet
|
|
66
59
|
end
|
|
67
60
|
|
|
68
61
|
::ActiveRecord::Associations::Preloader.class_eval do
|
|
@@ -87,6 +80,7 @@ module Bullet
|
|
|
87
80
|
alias_method :origin_find_with_associations, :find_with_associations
|
|
88
81
|
def find_with_associations
|
|
89
82
|
return origin_find_with_associations { |r| yield r } if block_given?
|
|
83
|
+
|
|
90
84
|
records = origin_find_with_associations
|
|
91
85
|
if Bullet.start?
|
|
92
86
|
associations = (eager_load_values + includes_values).uniq
|
|
@@ -185,6 +179,14 @@ module Bullet
|
|
|
185
179
|
origin_count_records
|
|
186
180
|
end
|
|
187
181
|
end
|
|
182
|
+
|
|
183
|
+
::ActiveRecord::Associations::BelongsToAssociation.class_eval do
|
|
184
|
+
def writer_with_bullet(record)
|
|
185
|
+
Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
|
|
186
|
+
writer_without_bullet(record)
|
|
187
|
+
end
|
|
188
|
+
alias_method_chain :writer, :bullet
|
|
189
|
+
end
|
|
188
190
|
end
|
|
189
191
|
end
|
|
190
192
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module ActiveRecord
|
|
3
5
|
def self.enable
|
|
@@ -42,21 +44,12 @@ module Bullet
|
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
::ActiveRecord::Persistence.class_eval do
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
47
|
+
def _create_record_with_bullet(*args)
|
|
48
|
+
_create_record_without_bullet(*args).tap do
|
|
49
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
|
49
50
|
end
|
|
50
51
|
end
|
|
51
|
-
alias_method_chain :
|
|
52
|
-
|
|
53
|
-
def save_with_bullet!(*args, &proc)
|
|
54
|
-
was_new_record = new_record?
|
|
55
|
-
save_without_bullet!(*args, &proc).tap do |result|
|
|
56
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
alias_method_chain :save!, :bullet
|
|
52
|
+
alias_method_chain :_create_record, :bullet
|
|
60
53
|
end
|
|
61
54
|
|
|
62
55
|
::ActiveRecord::Relation.class_eval do
|
|
@@ -102,6 +95,7 @@ module Bullet
|
|
|
102
95
|
alias_method :origin_find_with_associations, :find_with_associations
|
|
103
96
|
def find_with_associations
|
|
104
97
|
return origin_find_with_associations { |r| yield r } if block_given?
|
|
98
|
+
|
|
105
99
|
records = origin_find_with_associations
|
|
106
100
|
if Bullet.start?
|
|
107
101
|
associations = (eager_load_values + includes_values).uniq
|
|
@@ -139,6 +133,7 @@ module Bullet
|
|
|
139
133
|
key = aliases.column_alias(node, node.primary_key)
|
|
140
134
|
id = row[key]
|
|
141
135
|
next unless id.nil?
|
|
136
|
+
|
|
142
137
|
associations = node.reflection.name
|
|
143
138
|
Bullet::Detector::Association.add_object_associations(ar_parent, associations)
|
|
144
139
|
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
|
|
@@ -245,6 +240,14 @@ module Bullet
|
|
|
245
240
|
origin_count_records
|
|
246
241
|
end
|
|
247
242
|
end
|
|
243
|
+
|
|
244
|
+
::ActiveRecord::Associations::BelongsToAssociation.class_eval do
|
|
245
|
+
def writer_with_bullet(record)
|
|
246
|
+
Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
|
|
247
|
+
writer_without_bullet(record)
|
|
248
|
+
end
|
|
249
|
+
alias_method_chain :writer, :bullet
|
|
250
|
+
end
|
|
248
251
|
end
|
|
249
252
|
end
|
|
250
253
|
end
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module SaveWithBulletSupport
|
|
3
|
-
def
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
end
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def save!(*args)
|
|
11
|
-
was_new_record = new_record?
|
|
12
|
-
super(*args).tap do |result|
|
|
13
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
5
|
+
def _create_record(*)
|
|
6
|
+
super do
|
|
7
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
|
8
|
+
yield(self) if block_given?
|
|
14
9
|
end
|
|
15
10
|
end
|
|
16
11
|
end
|
|
@@ -80,6 +75,7 @@ module Bullet
|
|
|
80
75
|
# add includes in scope
|
|
81
76
|
def find_with_associations
|
|
82
77
|
return super { |r| yield r } if block_given?
|
|
78
|
+
|
|
83
79
|
records = super
|
|
84
80
|
if Bullet.start?
|
|
85
81
|
associations = (eager_load_values + includes_values).uniq
|
|
@@ -130,6 +126,7 @@ module Bullet
|
|
|
130
126
|
key = aliases.column_alias(node, node.primary_key)
|
|
131
127
|
id = row[key]
|
|
132
128
|
next unless id.nil?
|
|
129
|
+
|
|
133
130
|
associations = node.reflection.name
|
|
134
131
|
Bullet::Detector::Association.add_object_associations(ar_parent, associations)
|
|
135
132
|
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
|
|
@@ -166,11 +163,20 @@ module Bullet
|
|
|
166
163
|
|
|
167
164
|
if Bullet.start?
|
|
168
165
|
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
refl = reflection.through_reflection
|
|
167
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
|
|
168
|
+
association = owner.association refl.name
|
|
171
169
|
Array(association.target).each do |through_record|
|
|
172
170
|
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
|
173
171
|
end
|
|
172
|
+
|
|
173
|
+
if refl.through_reflection?
|
|
174
|
+
while refl.through_reflection?
|
|
175
|
+
refl = refl.through_reflection
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
|
|
179
|
+
end
|
|
174
180
|
end
|
|
175
181
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
|
176
182
|
if records.first.class.name !~ /^HABTM_/
|
|
@@ -236,6 +242,13 @@ module Bullet
|
|
|
236
242
|
super
|
|
237
243
|
end
|
|
238
244
|
end)
|
|
245
|
+
|
|
246
|
+
::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
|
|
247
|
+
def writer(record)
|
|
248
|
+
Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
|
|
249
|
+
super
|
|
250
|
+
end
|
|
251
|
+
end)
|
|
239
252
|
end
|
|
240
253
|
end
|
|
241
254
|
end
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module SaveWithBulletSupport
|
|
3
|
-
def
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
end
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def save!(*args)
|
|
11
|
-
was_new_record = new_record?
|
|
12
|
-
super(*args).tap do |result|
|
|
13
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
|
|
5
|
+
def _create_record(*)
|
|
6
|
+
super do
|
|
7
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
|
8
|
+
yield(self) if block_given?
|
|
14
9
|
end
|
|
15
10
|
end
|
|
16
11
|
end
|
|
@@ -80,6 +75,7 @@ module Bullet
|
|
|
80
75
|
# add includes in scope
|
|
81
76
|
def find_with_associations
|
|
82
77
|
return super { |r| yield r } if block_given?
|
|
78
|
+
|
|
83
79
|
records = super
|
|
84
80
|
if Bullet.start?
|
|
85
81
|
associations = (eager_load_values + includes_values).uniq
|
|
@@ -113,6 +109,7 @@ module Bullet
|
|
|
113
109
|
key = aliases.column_alias(node, node.primary_key)
|
|
114
110
|
id = row[key]
|
|
115
111
|
next unless id.nil?
|
|
112
|
+
|
|
116
113
|
associations = node.reflection.name
|
|
117
114
|
Bullet::Detector::Association.add_object_associations(ar_parent, associations)
|
|
118
115
|
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
|
|
@@ -149,11 +146,15 @@ module Bullet
|
|
|
149
146
|
|
|
150
147
|
if Bullet.start?
|
|
151
148
|
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
|
152
|
-
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
|
153
|
-
association = owner.association through_reflection.name
|
|
149
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
|
150
|
+
association = owner.association reflection.through_reflection.name
|
|
154
151
|
Array(association.target).each do |through_record|
|
|
155
152
|
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
|
156
153
|
end
|
|
154
|
+
|
|
155
|
+
if reflection.through_reflection != through_reflection
|
|
156
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
|
157
|
+
end
|
|
157
158
|
end
|
|
158
159
|
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
|
159
160
|
if records.first.class.name !~ /^HABTM_/
|
|
@@ -219,6 +220,13 @@ module Bullet
|
|
|
219
220
|
super
|
|
220
221
|
end
|
|
221
222
|
end)
|
|
223
|
+
|
|
224
|
+
::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
|
|
225
|
+
def writer(record)
|
|
226
|
+
Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
|
|
227
|
+
super
|
|
228
|
+
end
|
|
229
|
+
end)
|
|
222
230
|
end
|
|
223
231
|
end
|
|
224
232
|
end
|
data/lib/bullet/dependency.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module Dependency
|
|
3
5
|
def mongoid?
|
|
@@ -27,7 +29,7 @@ module Bullet
|
|
|
27
29
|
elsif active_record52?
|
|
28
30
|
'active_record52'
|
|
29
31
|
else
|
|
30
|
-
raise "Bullet does not support active_record #{::ActiveRecord::VERSION} yet"
|
|
32
|
+
raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
|
|
31
33
|
end
|
|
32
34
|
end
|
|
33
35
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module Detector
|
|
3
5
|
class Association < Base
|
|
@@ -7,7 +9,7 @@ module Bullet
|
|
|
7
9
|
return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
|
|
8
10
|
return unless object.primary_key_value
|
|
9
11
|
|
|
10
|
-
Bullet.debug('Detector::Association#add_object_associations'
|
|
12
|
+
Bullet.debug('Detector::Association#add_object_associations', "object: #{object.bullet_key}, associations: #{associations}")
|
|
11
13
|
object_associations.add(object.bullet_key, associations)
|
|
12
14
|
end
|
|
13
15
|
|
|
@@ -16,7 +18,7 @@ module Bullet
|
|
|
16
18
|
return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
|
|
17
19
|
return unless object.primary_key_value
|
|
18
20
|
|
|
19
|
-
Bullet.debug('Detector::Association#add_call_object_associations'
|
|
21
|
+
Bullet.debug('Detector::Association#add_call_object_associations', "object: #{object.bullet_key}, associations: #{associations}")
|
|
20
22
|
call_object_associations.add(object.bullet_key, associations)
|
|
21
23
|
end
|
|
22
24
|
|
data/lib/bullet/detector/base.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module Detector
|
|
3
5
|
class CounterCache < Base
|
|
@@ -16,6 +18,7 @@ module Bullet
|
|
|
16
18
|
def add_possible_objects(object_or_objects)
|
|
17
19
|
return unless Bullet.start?
|
|
18
20
|
return unless Bullet.counter_cache_enable?
|
|
21
|
+
|
|
19
22
|
objects = Array(object_or_objects)
|
|
20
23
|
return if objects.map(&:primary_key_value).compact.empty?
|
|
21
24
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module Detector
|
|
3
5
|
class NPlusOneQuery < Association
|
|
@@ -14,9 +16,10 @@ module Bullet
|
|
|
14
16
|
return unless Bullet.n_plus_one_query_enable?
|
|
15
17
|
return unless object.primary_key_value
|
|
16
18
|
return if inversed_objects.include?(object.bullet_key, associations)
|
|
19
|
+
|
|
17
20
|
add_call_object_associations(object, associations)
|
|
18
21
|
|
|
19
|
-
Bullet.debug('Detector::NPlusOneQuery#call_association'
|
|
22
|
+
Bullet.debug('Detector::NPlusOneQuery#call_association', "object: #{object.bullet_key}, associations: #{associations}")
|
|
20
23
|
if !excluded_stacktrace_path? && conditions_met?(object, associations)
|
|
21
24
|
Bullet.debug('detect n + 1 query', "object: #{object.bullet_key}, associations: #{associations}")
|
|
22
25
|
create_notification caller_in_project, object.class.to_s, associations
|
|
@@ -26,10 +29,11 @@ module Bullet
|
|
|
26
29
|
def add_possible_objects(object_or_objects)
|
|
27
30
|
return unless Bullet.start?
|
|
28
31
|
return unless Bullet.n_plus_one_query_enable?
|
|
32
|
+
|
|
29
33
|
objects = Array(object_or_objects)
|
|
30
34
|
return if objects.map(&:primary_key_value).compact.empty?
|
|
31
35
|
|
|
32
|
-
Bullet.debug('Detector::NPlusOneQuery#add_possible_objects'
|
|
36
|
+
Bullet.debug('Detector::NPlusOneQuery#add_possible_objects', "objects: #{objects.map(&:bullet_key).join(', ')}")
|
|
33
37
|
objects.each { |object| possible_objects.add object.bullet_key }
|
|
34
38
|
end
|
|
35
39
|
|
|
@@ -38,7 +42,7 @@ module Bullet
|
|
|
38
42
|
return unless Bullet.n_plus_one_query_enable?
|
|
39
43
|
return unless object.primary_key_value
|
|
40
44
|
|
|
41
|
-
Bullet.debug('Detector::NPlusOneQuery#add_impossible_object'
|
|
45
|
+
Bullet.debug('Detector::NPlusOneQuery#add_impossible_object', "object: #{object.bullet_key}")
|
|
42
46
|
impossible_objects.add object.bullet_key
|
|
43
47
|
end
|
|
44
48
|
|
|
@@ -47,7 +51,7 @@ module Bullet
|
|
|
47
51
|
return unless Bullet.n_plus_one_query_enable?
|
|
48
52
|
return unless object.primary_key_value
|
|
49
53
|
|
|
50
|
-
Bullet.debug('Detector::NPlusOneQuery#add_inversed_object'
|
|
54
|
+
Bullet.debug('Detector::NPlusOneQuery#add_inversed_object', "object: #{object.bullet_key}, association: #{association}")
|
|
51
55
|
inversed_objects.add object.bullet_key, association
|
|
52
56
|
end
|
|
53
57
|
|
|
@@ -67,14 +71,12 @@ module Bullet
|
|
|
67
71
|
# check if object => associations already exists in object_associations.
|
|
68
72
|
def association?(object, associations)
|
|
69
73
|
value = object_associations[object.bullet_key]
|
|
70
|
-
|
|
71
|
-
value.each do |v|
|
|
74
|
+
value&.each do |v|
|
|
72
75
|
# associations == v comparison order is important here because
|
|
73
76
|
# v variable might be a squeel node where :== method is redefined,
|
|
74
77
|
# so it does not compare values at all and return unexpected results
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
end
|
|
78
|
+
result = v.is_a?(Hash) ? v.key?(associations) : associations == v
|
|
79
|
+
return true if result
|
|
78
80
|
end
|
|
79
81
|
|
|
80
82
|
false
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module Detector
|
|
3
5
|
class UnusedEagerLoading < Association
|
|
@@ -73,6 +75,7 @@ module Bullet
|
|
|
73
75
|
eager_loadings.similarly_associated(bullet_key, associations).each do |related_bullet_key|
|
|
74
76
|
coa = call_object_associations[related_bullet_key]
|
|
75
77
|
next if coa.nil?
|
|
78
|
+
|
|
76
79
|
all.merge coa
|
|
77
80
|
end
|
|
78
81
|
all.to_a
|
data/lib/bullet/detector.rb
CHANGED
data/lib/bullet/ext/object.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
class Object
|
|
2
4
|
def bullet_key
|
|
3
5
|
"#{self.class}:#{primary_key_value}"
|
|
@@ -5,7 +7,7 @@ class Object
|
|
|
5
7
|
|
|
6
8
|
def primary_key_value
|
|
7
9
|
if self.class.respond_to?(:primary_keys) && self.class.primary_keys
|
|
8
|
-
self.class.primary_keys.map { |primary_key| send primary_key }.join(','
|
|
10
|
+
self.class.primary_keys.map { |primary_key| send primary_key }.join(',')
|
|
9
11
|
elsif self.class.respond_to?(:primary_key) && self.class.primary_key
|
|
10
12
|
send self.class.primary_key
|
|
11
13
|
else
|
data/lib/bullet/ext/string.rb
CHANGED
data/lib/bullet/mongoid4x.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Bullet
|
|
2
4
|
module Mongoid
|
|
3
5
|
def self.enable
|
|
@@ -21,13 +23,16 @@ module Bullet
|
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
def each(&block)
|
|
24
|
-
|
|
26
|
+
return to_enum unless block_given?
|
|
27
|
+
|
|
28
|
+
records = []
|
|
29
|
+
origin_each { |record| records << record }
|
|
25
30
|
if records.length > 1
|
|
26
31
|
Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
|
|
27
32
|
elsif records.size == 1
|
|
28
33
|
Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
|
|
29
34
|
end
|
|
30
|
-
|
|
35
|
+
records.each(&block)
|
|
31
36
|
end
|
|
32
37
|
|
|
33
38
|
def eager_load(docs)
|