bullet 5.1.0 → 5.4.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/.travis.yml +13 -13
- data/CHANGELOG.md +20 -2
- data/Gemfile.mongoid-2.4 +0 -2
- data/Gemfile.mongoid-2.5 +0 -2
- data/Gemfile.mongoid-2.6 +0 -2
- data/Gemfile.mongoid-2.7 +0 -2
- data/Gemfile.mongoid-2.8 +0 -2
- data/Gemfile.mongoid-3.0 +0 -2
- data/Gemfile.mongoid-3.1 +0 -2
- data/Gemfile.mongoid-4.0 +0 -2
- data/Gemfile.mongoid-5.0 +0 -2
- data/Gemfile.rails-3.0 +0 -2
- data/Gemfile.rails-3.1 +0 -2
- data/Gemfile.rails-3.2 +0 -2
- data/Gemfile.rails-4.0 +0 -2
- data/Gemfile.rails-4.1 +0 -2
- data/Gemfile.rails-4.2 +0 -2
- data/Gemfile.rails-5.0 +1 -3
- data/README.md +5 -4
- data/lib/bullet/active_record3.rb +34 -3
- data/lib/bullet/active_record3x.rb +34 -3
- data/lib/bullet/active_record4.rb +34 -3
- data/lib/bullet/active_record41.rb +19 -0
- data/lib/bullet/active_record42.rb +37 -0
- data/lib/bullet/active_record5.rb +61 -48
- data/lib/bullet/dependency.rb +7 -1
- data/lib/bullet/detector/n_plus_one_query.rb +1 -15
- data/lib/bullet/detector/unused_eager_loading.rb +6 -3
- data/lib/bullet/notification/unused_eager_loading.rb +12 -0
- data/lib/bullet/rack.rb +2 -2
- data/lib/bullet/stack_trace_filter.rb +34 -0
- data/lib/bullet/version.rb +1 -1
- data/lib/bullet.rb +17 -2
- data/spec/bullet/detector/n_plus_one_query_spec.rb +5 -5
- data/spec/bullet/detector/unused_eager_loading_spec.rb +3 -1
- data/spec/bullet/notification/unused_eager_loading_spec.rb +1 -1
- data/spec/bullet/rack_spec.rb +4 -4
- data/spec/bullet_spec.rb +43 -0
- data/spec/integration/active_record3/association_spec.rb +21 -1
- data/spec/integration/active_record4/association_spec.rb +21 -1
- data/spec/integration/active_record5/association_spec.rb +21 -1
- data/spec/spec_helper.rb +0 -3
- data/spec/support/sqlite_seed.rb +1 -0
- metadata +3 -2
|
@@ -20,9 +20,9 @@ module Bullet
|
|
|
20
20
|
require 'active_record'
|
|
21
21
|
::ActiveRecord::Base.class_eval do
|
|
22
22
|
class <<self
|
|
23
|
-
alias_method :
|
|
24
|
-
def
|
|
25
|
-
result =
|
|
23
|
+
alias_method :origin_find_by_sql, :find_by_sql
|
|
24
|
+
def find_by_sql(sql, binds = [], preparable: nil)
|
|
25
|
+
result = origin_find_by_sql(sql, binds, preparable: nil)
|
|
26
26
|
if Bullet.start?
|
|
27
27
|
if result.is_a? Array
|
|
28
28
|
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
|
@@ -40,38 +40,30 @@ module Bullet
|
|
|
40
40
|
::ActiveRecord::Base.prepend(SaveWithBulletSupport)
|
|
41
41
|
|
|
42
42
|
::ActiveRecord::Relation.class_eval do
|
|
43
|
-
alias_method :
|
|
43
|
+
alias_method :origin_records, :records
|
|
44
44
|
# if select a collection of objects, then these objects have possible to cause N+1 query.
|
|
45
45
|
# if select only one object, then the only one object has impossible to cause N+1 query.
|
|
46
|
-
def
|
|
47
|
-
|
|
46
|
+
def records
|
|
47
|
+
result = origin_records
|
|
48
48
|
if Bullet.start?
|
|
49
|
-
if
|
|
50
|
-
if
|
|
51
|
-
Bullet::Detector::NPlusOneQuery.add_possible_objects(
|
|
52
|
-
Bullet::Detector::CounterCache.add_possible_objects(
|
|
53
|
-
elsif
|
|
54
|
-
Bullet::Detector::NPlusOneQuery.add_impossible_object(
|
|
55
|
-
Bullet::Detector::CounterCache.add_impossible_object(
|
|
49
|
+
if result.first.class.name !~ /^HABTM_/
|
|
50
|
+
if result.size > 1
|
|
51
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
|
52
|
+
Bullet::Detector::CounterCache.add_possible_objects(result)
|
|
53
|
+
elsif result.size == 1
|
|
54
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
|
|
55
|
+
Bullet::Detector::CounterCache.add_impossible_object(result.first)
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
|
-
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
::ActiveRecord::Associations::Association.class_eval do
|
|
64
|
-
alias_method :origin_initialize, :initialize
|
|
65
|
-
def initialize(owner, reflection)
|
|
66
|
-
origin_initialize(owner, reflection)
|
|
67
|
-
reflection.set_owner owner
|
|
59
|
+
result
|
|
68
60
|
end
|
|
69
61
|
end
|
|
70
62
|
|
|
71
63
|
::ActiveRecord::Associations::Preloader.class_eval do
|
|
72
|
-
alias_method :
|
|
64
|
+
alias_method :origin_preloaders_for_one, :preloaders_for_one
|
|
73
65
|
|
|
74
|
-
def
|
|
66
|
+
def preloaders_for_one(association, records, scope)
|
|
75
67
|
if Bullet.start?
|
|
76
68
|
records.compact!
|
|
77
69
|
if records.first.class.name !~ /^HABTM_/
|
|
@@ -81,7 +73,7 @@ module Bullet
|
|
|
81
73
|
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
|
|
82
74
|
end
|
|
83
75
|
end
|
|
84
|
-
|
|
76
|
+
origin_preloaders_for_one(association, records, scope)
|
|
85
77
|
end
|
|
86
78
|
end
|
|
87
79
|
|
|
@@ -104,6 +96,7 @@ module Bullet
|
|
|
104
96
|
|
|
105
97
|
::ActiveRecord::Associations::JoinDependency.class_eval do
|
|
106
98
|
alias_method :origin_instantiate, :instantiate
|
|
99
|
+
alias_method :origin_construct, :construct
|
|
107
100
|
alias_method :origin_construct_model, :construct_model
|
|
108
101
|
|
|
109
102
|
def instantiate(result_set, aliases)
|
|
@@ -119,6 +112,27 @@ module Bullet
|
|
|
119
112
|
records
|
|
120
113
|
end
|
|
121
114
|
|
|
115
|
+
def construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
|
|
116
|
+
if Bullet.start?
|
|
117
|
+
unless ar_parent.nil?
|
|
118
|
+
parent.children.each do |node|
|
|
119
|
+
key = aliases.column_alias(node, node.primary_key)
|
|
120
|
+
id = row[key]
|
|
121
|
+
if id.nil?
|
|
122
|
+
associations = node.reflection.name
|
|
123
|
+
Bullet::Detector::Association.add_object_associations(ar_parent, associations)
|
|
124
|
+
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
|
|
125
|
+
@bullet_eager_loadings[ar_parent.class] ||= {}
|
|
126
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
|
|
127
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] << associations
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
origin_construct(ar_parent, parent, row, rs, seen, model_cache, aliases)
|
|
134
|
+
end
|
|
135
|
+
|
|
122
136
|
# call join associations
|
|
123
137
|
def construct_model(record, node, row, model_cache, id, aliases)
|
|
124
138
|
result = origin_construct_model(record, node, row, model_cache, id, aliases)
|
|
@@ -143,7 +157,14 @@ module Bullet
|
|
|
143
157
|
records = origin_load_target
|
|
144
158
|
|
|
145
159
|
if Bullet.start?
|
|
146
|
-
|
|
160
|
+
if self.is_a? ::ActiveRecord::Associations::ThroughAssociation
|
|
161
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
|
162
|
+
association = self.owner.association self.through_reflection.name
|
|
163
|
+
Array(association.target).each do |through_record|
|
|
164
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
|
147
168
|
if records.first.class.name !~ /^HABTM_/
|
|
148
169
|
if records.size > 1
|
|
149
170
|
Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
|
|
@@ -159,8 +180,8 @@ module Bullet
|
|
|
159
180
|
|
|
160
181
|
alias_method :origin_empty?, :empty?
|
|
161
182
|
def empty?
|
|
162
|
-
if Bullet.start? &&
|
|
163
|
-
Bullet::Detector::NPlusOneQuery.call_association(
|
|
183
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
|
184
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
164
185
|
end
|
|
165
186
|
origin_empty?
|
|
166
187
|
end
|
|
@@ -168,7 +189,7 @@ module Bullet
|
|
|
168
189
|
alias_method :origin_include?, :include?
|
|
169
190
|
def include?(object)
|
|
170
191
|
if Bullet.start?
|
|
171
|
-
Bullet::Detector::NPlusOneQuery.call_association(
|
|
192
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
172
193
|
end
|
|
173
194
|
origin_include?(object)
|
|
174
195
|
end
|
|
@@ -180,9 +201,9 @@ module Bullet
|
|
|
180
201
|
def reader(force_reload = false)
|
|
181
202
|
result = origin_reader(force_reload)
|
|
182
203
|
if Bullet.start?
|
|
183
|
-
if
|
|
184
|
-
Bullet::Detector::NPlusOneQuery.call_association(
|
|
185
|
-
if Bullet::Detector::NPlusOneQuery.impossible?(
|
|
204
|
+
if owner.class.name !~ /^HABTM_/ && !@inversed
|
|
205
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
206
|
+
if Bullet::Detector::NPlusOneQuery.impossible?(owner)
|
|
186
207
|
Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
|
|
187
208
|
else
|
|
188
209
|
Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
|
|
@@ -196,28 +217,20 @@ module Bullet
|
|
|
196
217
|
::ActiveRecord::Associations::HasManyAssociation.class_eval do
|
|
197
218
|
alias_method :origin_many_empty?, :empty?
|
|
198
219
|
def empty?
|
|
199
|
-
Thread.current[:bullet_collection_empty] = true
|
|
200
220
|
result = origin_many_empty?
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
|
|
221
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
|
222
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
|
204
223
|
end
|
|
205
224
|
result
|
|
206
225
|
end
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
::ActiveRecord::Reflection::AbstractReflection.class_eval do
|
|
210
|
-
def set_owner(owner)
|
|
211
|
-
@owner = owner
|
|
212
|
-
end
|
|
213
226
|
|
|
214
|
-
alias_method :
|
|
215
|
-
def
|
|
216
|
-
result =
|
|
217
|
-
if Bullet.start? && !result && !
|
|
218
|
-
Bullet::Detector::CounterCache.add_counter_cache(
|
|
227
|
+
alias_method :origin_count_records, :count_records
|
|
228
|
+
def count_records
|
|
229
|
+
result = reflection.has_cached_counter?
|
|
230
|
+
if Bullet.start? && !result && !self.is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
|
231
|
+
Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
|
|
219
232
|
end
|
|
220
|
-
|
|
233
|
+
origin_count_records
|
|
221
234
|
end
|
|
222
235
|
end
|
|
223
236
|
end
|
data/lib/bullet/dependency.rb
CHANGED
|
@@ -26,6 +26,8 @@ module Bullet
|
|
|
26
26
|
'active_record42'
|
|
27
27
|
elsif active_record50?
|
|
28
28
|
'active_record5'
|
|
29
|
+
elsif active_record51?
|
|
30
|
+
'active_record5'
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
end
|
|
@@ -84,8 +86,12 @@ module Bullet
|
|
|
84
86
|
active_record5? && ::ActiveRecord::VERSION::MINOR == 0
|
|
85
87
|
end
|
|
86
88
|
|
|
89
|
+
def active_record51?
|
|
90
|
+
active_record5? && ::ActiveRecord::VERSION::MINOR == 1
|
|
91
|
+
end
|
|
92
|
+
|
|
87
93
|
def mongoid2x?
|
|
88
|
-
mongoid? && ::Mongoid::VERSION =~ /\A2\.[4-
|
|
94
|
+
mongoid? && ::Mongoid::VERSION =~ /\A2\.[4-9]/
|
|
89
95
|
end
|
|
90
96
|
|
|
91
97
|
def mongoid3x?
|
|
@@ -2,6 +2,7 @@ module Bullet
|
|
|
2
2
|
module Detector
|
|
3
3
|
class NPlusOneQuery < Association
|
|
4
4
|
extend Dependency
|
|
5
|
+
extend StackTraceFilter
|
|
5
6
|
|
|
6
7
|
class <<self
|
|
7
8
|
# executed when object.assocations is called.
|
|
@@ -87,21 +88,6 @@ module Bullet
|
|
|
87
88
|
Bullet.notification_collector.add(notice)
|
|
88
89
|
end
|
|
89
90
|
end
|
|
90
|
-
|
|
91
|
-
def caller_in_project
|
|
92
|
-
app_root = rails? ? Rails.root.to_s : Dir.pwd
|
|
93
|
-
vendor_root = app_root + "/vendor"
|
|
94
|
-
caller.select do |c|
|
|
95
|
-
c.include?(app_root) && !c.include?(vendor_root) ||
|
|
96
|
-
Bullet.stacktrace_includes.any? { |include| c.include?(include) }
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def excluded_stacktrace_path?
|
|
101
|
-
Bullet.stacktrace_excludes.any? do |excluded_path|
|
|
102
|
-
caller_in_project.any? { |c| c.include?(excluded_path) }
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
91
|
end
|
|
106
92
|
end
|
|
107
93
|
end
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
module Bullet
|
|
2
2
|
module Detector
|
|
3
3
|
class UnusedEagerLoading < Association
|
|
4
|
+
extend Dependency
|
|
5
|
+
extend StackTraceFilter
|
|
6
|
+
|
|
4
7
|
class <<self
|
|
5
8
|
# check if there are unused preload associations.
|
|
6
9
|
# get related_objects from eager_loadings associated with object and associations
|
|
@@ -15,7 +18,7 @@ module Bullet
|
|
|
15
18
|
next if object_association_diff.empty?
|
|
16
19
|
|
|
17
20
|
Bullet.debug("detect unused preload", "object: #{bullet_key}, associations: #{object_association_diff}")
|
|
18
|
-
create_notification bullet_key.bullet_class_name, object_association_diff
|
|
21
|
+
create_notification(caller_in_project, bullet_key.bullet_class_name, object_association_diff)
|
|
19
22
|
end
|
|
20
23
|
end
|
|
21
24
|
|
|
@@ -53,11 +56,11 @@ module Bullet
|
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
private
|
|
56
|
-
def create_notification(klazz, associations)
|
|
59
|
+
def create_notification(callers, klazz, associations)
|
|
57
60
|
notify_associations = Array(associations) - Bullet.get_whitelist_associations(:unused_eager_loading, klazz)
|
|
58
61
|
|
|
59
62
|
if notify_associations.present?
|
|
60
|
-
notice = Bullet::Notification::UnusedEagerLoading.new(klazz, notify_associations)
|
|
63
|
+
notice = Bullet::Notification::UnusedEagerLoading.new(callers, klazz, notify_associations)
|
|
61
64
|
Bullet.notification_collector.add(notice)
|
|
62
65
|
end
|
|
63
66
|
end
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
module Bullet
|
|
2
2
|
module Notification
|
|
3
3
|
class UnusedEagerLoading < Base
|
|
4
|
+
def initialize(callers, base_class, associations, path = nil)
|
|
5
|
+
super(base_class, associations, path)
|
|
6
|
+
|
|
7
|
+
@callers = callers
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def notification_data
|
|
11
|
+
super.merge(
|
|
12
|
+
:backtrace => @callers
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
4
16
|
def body
|
|
5
17
|
"#{klazz_associations_str}\n Remove from your finder: #{associations_str}"
|
|
6
18
|
end
|
data/lib/bullet/rack.rb
CHANGED
|
@@ -80,8 +80,8 @@ module Bullet
|
|
|
80
80
|
data-is-bullet-footer ondblclick="this.parentNode.removeChild(this);" style="position: fixed; bottom: 0pt; left: 0pt; cursor: pointer; border-style: solid; border-color: rgb(153, 153, 153);
|
|
81
81
|
-moz-border-top-colors: none; -moz-border-right-colors: none; -moz-border-bottom-colors: none;
|
|
82
82
|
-moz-border-left-colors: none; -moz-border-image: none; border-width: 2pt 2pt 0px 0px;
|
|
83
|
-
padding: 5px; border-radius: 0pt 10pt 0pt 0px; background: none repeat scroll 0% 0% rgba(200, 200, 200, 0.8);
|
|
84
|
-
color: rgb(119, 119, 119); font-size:
|
|
83
|
+
padding: 3px 5px; border-radius: 0pt 10pt 0pt 0px; background: none repeat scroll 0% 0% rgba(200, 200, 200, 0.8);
|
|
84
|
+
color: rgb(119, 119, 119); font-size: 16px; font-family: 'Arial', sans-serif; z-index:9999;"
|
|
85
85
|
EOF
|
|
86
86
|
end
|
|
87
87
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Bullet
|
|
2
|
+
module StackTraceFilter
|
|
3
|
+
VENDOR_PATH = "/vendor"
|
|
4
|
+
|
|
5
|
+
def caller_in_project
|
|
6
|
+
app_root = rails? ? Rails.root.to_s : Dir.pwd
|
|
7
|
+
vendor_root = app_root + VENDOR_PATH
|
|
8
|
+
caller.select do |caller_path|
|
|
9
|
+
caller_path.include?(app_root) && !caller_path.include?(vendor_root) ||
|
|
10
|
+
Bullet.stacktrace_includes.any? do |include_pattern|
|
|
11
|
+
case include_pattern
|
|
12
|
+
when String
|
|
13
|
+
caller_path.include?(include_pattern)
|
|
14
|
+
when Regexp
|
|
15
|
+
caller_path =~ include_pattern
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def excluded_stacktrace_path?
|
|
22
|
+
Bullet.stacktrace_excludes.any? do |exclude_pattern|
|
|
23
|
+
caller_in_project.any? do |caller_path|
|
|
24
|
+
case exclude_pattern
|
|
25
|
+
when String
|
|
26
|
+
caller_path.include?(exclude_pattern)
|
|
27
|
+
when Regexp
|
|
28
|
+
caller_path =~ exclude_pattern
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/bullet/version.rb
CHANGED
data/lib/bullet.rb
CHANGED
|
@@ -4,6 +4,7 @@ require 'uniform_notifier'
|
|
|
4
4
|
require 'bullet/ext/object'
|
|
5
5
|
require 'bullet/ext/string'
|
|
6
6
|
require 'bullet/dependency'
|
|
7
|
+
require 'bullet/stack_trace_filter'
|
|
7
8
|
|
|
8
9
|
module Bullet
|
|
9
10
|
extend Dependency
|
|
@@ -166,8 +167,9 @@ module Bullet
|
|
|
166
167
|
end
|
|
167
168
|
|
|
168
169
|
def perform_out_of_channel_notifications(env = {})
|
|
170
|
+
request_uri = env['REQUEST_URI'] || build_request_uri(env)
|
|
169
171
|
for_each_active_notifier_with_notification do |notification|
|
|
170
|
-
notification.url =
|
|
172
|
+
notification.url = request_uri
|
|
171
173
|
notification.notify_out_of_channel
|
|
172
174
|
end
|
|
173
175
|
end
|
|
@@ -190,17 +192,22 @@ module Bullet
|
|
|
190
192
|
end
|
|
191
193
|
|
|
192
194
|
def profile
|
|
195
|
+
return_value = nil
|
|
193
196
|
if Bullet.enable?
|
|
194
197
|
begin
|
|
195
198
|
Bullet.start_request
|
|
196
199
|
|
|
197
|
-
yield
|
|
200
|
+
return_value = yield
|
|
198
201
|
|
|
199
202
|
Bullet.perform_out_of_channel_notifications if Bullet.notification?
|
|
200
203
|
ensure
|
|
201
204
|
Bullet.end_request
|
|
202
205
|
end
|
|
206
|
+
else
|
|
207
|
+
return_value = yield
|
|
203
208
|
end
|
|
209
|
+
|
|
210
|
+
return_value
|
|
204
211
|
end
|
|
205
212
|
|
|
206
213
|
private
|
|
@@ -212,5 +219,13 @@ module Bullet
|
|
|
212
219
|
end
|
|
213
220
|
end
|
|
214
221
|
end
|
|
222
|
+
|
|
223
|
+
def build_request_uri(env)
|
|
224
|
+
if env['QUERY_STRING'].present?
|
|
225
|
+
"#{env['PATH_INFO']}?#{env['QUERY_STRING']}"
|
|
226
|
+
else
|
|
227
|
+
env['PATH_INFO']
|
|
228
|
+
end
|
|
229
|
+
end
|
|
215
230
|
end
|
|
216
231
|
end
|
|
@@ -87,7 +87,7 @@ module Bullet
|
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
context "stacktrace_excludes" do
|
|
90
|
-
before { Bullet.stacktrace_excludes = [
|
|
90
|
+
before { Bullet.stacktrace_excludes = [ /def/ ] }
|
|
91
91
|
after { Bullet.stacktrace_excludes = nil }
|
|
92
92
|
|
|
93
93
|
it "should not create notification when stacktrace contains paths that are in the exclude list" do
|
|
@@ -114,17 +114,17 @@ module Bullet
|
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
context "stacktrace_includes" do
|
|
117
|
-
before { Bullet.stacktrace_includes = [ 'def' ] }
|
|
117
|
+
before { Bullet.stacktrace_includes = [ 'def', /xyz/ ] }
|
|
118
118
|
after { Bullet.stacktrace_includes = nil }
|
|
119
119
|
|
|
120
120
|
it "should include paths that are in the stacktrace_include list" do
|
|
121
121
|
in_project = File.join(Dir.pwd, 'abc', 'abc.rb')
|
|
122
|
-
|
|
122
|
+
included_gems = ['/def/def.rb', 'xyz/xyz.rb']
|
|
123
123
|
excluded_gem = '/ghi/ghi.rb'
|
|
124
124
|
|
|
125
|
-
expect(NPlusOneQuery).to receive(:caller).and_return([in_project,
|
|
125
|
+
expect(NPlusOneQuery).to receive(:caller).and_return([in_project, *included_gems, excluded_gem])
|
|
126
126
|
expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
|
|
127
|
-
expect(NPlusOneQuery).to receive(:create_notification).with([in_project,
|
|
127
|
+
expect(NPlusOneQuery).to receive(:create_notification).with([in_project, *included_gems], "Post", :association)
|
|
128
128
|
NPlusOneQuery.call_association(@post, :association)
|
|
129
129
|
end
|
|
130
130
|
end
|
|
@@ -39,9 +39,11 @@ module Bullet
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
context ".check_unused_preload_associations" do
|
|
42
|
+
let(:paths) { ["/dir1", "/dir1/subdir"] }
|
|
42
43
|
it "should create notification if object_association_diff is not empty" do
|
|
43
44
|
UnusedEagerLoading.add_object_associations(@post, :association)
|
|
44
|
-
|
|
45
|
+
allow(UnusedEagerLoading).to receive(:caller_in_project).and_return(paths)
|
|
46
|
+
expect(UnusedEagerLoading).to receive(:create_notification).with(paths, "Post", [:association])
|
|
45
47
|
UnusedEagerLoading.check_unused_preload_associations
|
|
46
48
|
end
|
|
47
49
|
|
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
|
3
3
|
module Bullet
|
|
4
4
|
module Notification
|
|
5
5
|
describe UnusedEagerLoading do
|
|
6
|
-
subject { UnusedEagerLoading.new(Post, [:comments, :votes], "path") }
|
|
6
|
+
subject { UnusedEagerLoading.new([""], Post, [:comments, :votes], "path") }
|
|
7
7
|
|
|
8
8
|
it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Remove from your finder: :includes => [:comments, :votes]") }
|
|
9
9
|
it { expect(subject.title).to eq("Unused Eager Loading in path") }
|
data/spec/bullet/rack_spec.rb
CHANGED
|
@@ -60,7 +60,7 @@ module Bullet
|
|
|
60
60
|
it "should return original response body" do
|
|
61
61
|
expected_response = Support::ResponseDouble.new "Actual body"
|
|
62
62
|
app.response = expected_response
|
|
63
|
-
_, _, response = middleware.call(
|
|
63
|
+
_, _, response = middleware.call({})
|
|
64
64
|
expect(response).to eq(expected_response)
|
|
65
65
|
end
|
|
66
66
|
|
|
@@ -68,7 +68,7 @@ module Bullet
|
|
|
68
68
|
expect(Bullet).to receive(:notification?).and_return(true)
|
|
69
69
|
expect(Bullet).to receive(:gather_inline_notifications).and_return("<bullet></bullet>")
|
|
70
70
|
expect(Bullet).to receive(:perform_out_of_channel_notifications)
|
|
71
|
-
status, headers, response = middleware.call(
|
|
71
|
+
status, headers, response = middleware.call({"Content-Type" => "text/html"})
|
|
72
72
|
expect(headers["Content-Length"]).to eq("56")
|
|
73
73
|
expect(response).to eq(["<html><head></head><body><bullet></bullet></body></html>"])
|
|
74
74
|
end
|
|
@@ -79,7 +79,7 @@ module Bullet
|
|
|
79
79
|
app.response = response
|
|
80
80
|
expect(Bullet).to receive(:notification?).and_return(true)
|
|
81
81
|
expect(Bullet).to receive(:gather_inline_notifications).and_return("<bullet></bullet>")
|
|
82
|
-
status, headers, response = middleware.call(
|
|
82
|
+
status, headers, response = middleware.call({"Content-Type" => "text/html"})
|
|
83
83
|
expect(headers["Content-Length"]).to eq("58")
|
|
84
84
|
end
|
|
85
85
|
end
|
|
@@ -89,7 +89,7 @@ module Bullet
|
|
|
89
89
|
|
|
90
90
|
it "should not call Bullet.start_request" do
|
|
91
91
|
expect(Bullet).not_to receive(:start_request)
|
|
92
|
-
middleware.call(
|
|
92
|
+
middleware.call({})
|
|
93
93
|
end
|
|
94
94
|
end
|
|
95
95
|
end
|
data/spec/bullet_spec.rb
CHANGED
|
@@ -94,4 +94,47 @@ describe Bullet, focused: true do
|
|
|
94
94
|
end
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
|
+
|
|
98
|
+
describe '#perform_out_of_channel_notifications' do
|
|
99
|
+
let(:notification) { double }
|
|
100
|
+
|
|
101
|
+
before do
|
|
102
|
+
allow(Bullet).to receive(:for_each_active_notifier_with_notification).and_yield(notification)
|
|
103
|
+
allow(notification).to receive(:notify_out_of_channel)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
context 'when called with no args' do
|
|
107
|
+
it 'should notification.url is nil' do
|
|
108
|
+
expect(notification).to receive(:url=).with(nil)
|
|
109
|
+
Bullet.perform_out_of_channel_notifications
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
context 'when called with Rack environment hash' do
|
|
114
|
+
let(:env) {
|
|
115
|
+
{
|
|
116
|
+
'PATH_INFO' => '/path',
|
|
117
|
+
'QUERY_STRING' => 'foo=bar',
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
context "when env['REQUEST_URI'] is nil" do
|
|
122
|
+
before { env['REQUEST_URI'] = nil }
|
|
123
|
+
|
|
124
|
+
it 'should notification.url is built' do
|
|
125
|
+
expect(notification).to receive(:url=).with('/path?foo=bar')
|
|
126
|
+
Bullet.perform_out_of_channel_notifications(env)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context "when env['REQUEST_URI'] is present" do
|
|
131
|
+
before { env['REQUEST_URI'] = 'http://example.com/path' }
|
|
132
|
+
|
|
133
|
+
it "should notification.url is env['REQUEST_URI']" do
|
|
134
|
+
expect(notification).to receive(:url=).with(env['REQUEST_URI'])
|
|
135
|
+
Bullet.perform_out_of_channel_notifications(env)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
97
140
|
end
|
|
@@ -13,6 +13,16 @@ if !mongoid? && active_record3?
|
|
|
13
13
|
expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
it "should detect non preload post => comments for find_by_sql" do
|
|
17
|
+
Post.find_by_sql("SELECT * FROM posts").each do |post|
|
|
18
|
+
post.comments.map(&:name)
|
|
19
|
+
end
|
|
20
|
+
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
|
21
|
+
expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
|
|
22
|
+
|
|
23
|
+
expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
|
|
24
|
+
end
|
|
25
|
+
|
|
16
26
|
it "should detect preload with post => comments" do
|
|
17
27
|
Post.includes(:comments).each do |post|
|
|
18
28
|
post.comments.map(&:name)
|
|
@@ -214,7 +224,7 @@ if !mongoid? && active_record3?
|
|
|
214
224
|
context "post => comment" do
|
|
215
225
|
it "should detect unused preload with post => comments" do
|
|
216
226
|
Post.includes(:comments).each do |post|
|
|
217
|
-
post.comments.first.name
|
|
227
|
+
post.comments.first.name if post.comments.first
|
|
218
228
|
end
|
|
219
229
|
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
|
220
230
|
expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :comments)
|
|
@@ -453,6 +463,16 @@ if !mongoid? && active_record3?
|
|
|
453
463
|
|
|
454
464
|
expect(Bullet::Detector::Association).to be_completely_preloading_associations
|
|
455
465
|
end
|
|
466
|
+
|
|
467
|
+
it "should detect non preload student => teachers with empty?" do
|
|
468
|
+
Student.all.each do |student|
|
|
469
|
+
student.teachers.empty?
|
|
470
|
+
end
|
|
471
|
+
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
|
472
|
+
expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
|
|
473
|
+
|
|
474
|
+
expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Student, :teachers)
|
|
475
|
+
end
|
|
456
476
|
end
|
|
457
477
|
end
|
|
458
478
|
|
|
@@ -13,6 +13,16 @@ if !mongoid? && active_record4?
|
|
|
13
13
|
expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
it "should detect non preload post => comments for find_by_sql" do
|
|
17
|
+
Post.find_by_sql("SELECT * FROM posts").each do |post|
|
|
18
|
+
post.comments.map(&:name)
|
|
19
|
+
end
|
|
20
|
+
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
|
21
|
+
expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
|
|
22
|
+
|
|
23
|
+
expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
|
|
24
|
+
end
|
|
25
|
+
|
|
16
26
|
it "should detect preload with post => comments" do
|
|
17
27
|
Post.includes(:comments).each do |post|
|
|
18
28
|
post.comments.map(&:name)
|
|
@@ -214,7 +224,7 @@ if !mongoid? && active_record4?
|
|
|
214
224
|
context "post => comment" do
|
|
215
225
|
it "should detect unused preload with post => comments" do
|
|
216
226
|
Post.includes(:comments).each do |post|
|
|
217
|
-
post.comments.first.name
|
|
227
|
+
post.comments.first.name if post.comments.first
|
|
218
228
|
end
|
|
219
229
|
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
|
220
230
|
expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :comments)
|
|
@@ -465,6 +475,16 @@ if !mongoid? && active_record4?
|
|
|
465
475
|
|
|
466
476
|
expect(Bullet::Detector::Association).to be_completely_preloading_associations
|
|
467
477
|
end
|
|
478
|
+
|
|
479
|
+
it "should detect non preload student => teachers with empty?" do
|
|
480
|
+
Student.all.each do |student|
|
|
481
|
+
student.teachers.empty?
|
|
482
|
+
end
|
|
483
|
+
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
|
484
|
+
expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
|
|
485
|
+
|
|
486
|
+
expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Student, :teachers)
|
|
487
|
+
end
|
|
468
488
|
end
|
|
469
489
|
end
|
|
470
490
|
|