bullet 5.9.0 → 6.0.1
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 +5 -5
- data/.travis.yml +19 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile.rails-4.0 +1 -1
- data/Gemfile.rails-4.1 +1 -1
- data/Gemfile.rails-4.2 +1 -1
- data/Gemfile.rails-5.0 +1 -1
- data/Gemfile.rails-5.1 +1 -1
- data/Gemfile.rails-5.2 +1 -1
- data/Gemfile.rails-6.0 +15 -0
- data/README.md +19 -7
- data/lib/bullet.rb +19 -3
- data/lib/bullet/active_job.rb +15 -0
- data/lib/bullet/active_record4.rb +1 -10
- data/lib/bullet/active_record41.rb +0 -8
- data/lib/bullet/active_record42.rb +0 -8
- data/lib/bullet/active_record5.rb +1 -10
- data/lib/bullet/active_record52.rb +0 -7
- data/lib/bullet/active_record60.rb +245 -0
- data/lib/bullet/bullet_xhr.js +69 -0
- data/lib/bullet/dependency.rb +10 -4
- data/lib/bullet/detector/association.rb +2 -2
- data/lib/bullet/detector/counter_cache.rb +3 -3
- data/lib/bullet/detector/n_plus_one_query.rb +4 -4
- data/lib/bullet/detector/unused_eager_loading.rb +1 -1
- data/lib/bullet/ext/object.rb +4 -2
- data/lib/bullet/rack.rb +37 -20
- data/lib/bullet/stack_trace_filter.rb +2 -3
- data/lib/bullet/version.rb +1 -1
- data/spec/bullet/ext/object_spec.rb +9 -4
- data/spec/bullet/rack_spec.rb +12 -3
- data/spec/integration/active_record/association_spec.rb +3 -14
- data/spec/integration/counter_cache_spec.rb +1 -1
- data/test.sh +1 -0
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7f255102db3ae1250632db2b30a9e6f1bce87dab49b4dabee73709ffde82a4e0
|
4
|
+
data.tar.gz: 025ab0e3513546a56e984aa83a0b925d27e631bdfe61feb694b3e21ecfb6ffda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23d701691dc1f2286ec11ffb26f548878bfa7ddd2ea8f20d97bb4c64df4e3a7a10f54adb16fa7cacd8bb8807dd1804e349c1b889e32530cbb7c57432ceec17da
|
7
|
+
data.tar.gz: 281a4a6619695a7db4098f1ed62066cd4e81cf9c2c3bf33fa83f87a205a5c4779e9c8125143a78ca482247ed2a271465b3011af84a5dfc67753cbad2357ee2ae
|
data/.travis.yml
CHANGED
@@ -2,11 +2,30 @@ sudo: false
|
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
4
|
- 2.3.0
|
5
|
+
- 2.6.0
|
5
6
|
gemfile:
|
7
|
+
- Gemfile.rails-6.0
|
8
|
+
- Gemfile.rails-5.2
|
6
9
|
- Gemfile.rails-5.1
|
7
10
|
- Gemfile.rails-5.0
|
8
11
|
- Gemfile.rails-4.2
|
9
12
|
- Gemfile.rails-4.1
|
10
13
|
- Gemfile.rails-4.0
|
14
|
+
matrix:
|
15
|
+
exclude:
|
16
|
+
- rvm: 2.3.0
|
17
|
+
gemfile: Gemfile.rails-6.0
|
18
|
+
- rvm: 2.6.0
|
19
|
+
gemfile: Gemfile.rails-5.2
|
20
|
+
- rvm: 2.6.0
|
21
|
+
gemfile: Gemfile.rails-5.1
|
22
|
+
- rvm: 2.6.0
|
23
|
+
gemfile: Gemfile.rails-5.0
|
24
|
+
- rvm: 2.6.0
|
25
|
+
gemfile: Gemfile.rails-4.2
|
26
|
+
- rvm: 2.6.0
|
27
|
+
gemfile: Gemfile.rails-4.1
|
28
|
+
- rvm: 2.6.0
|
29
|
+
gemfile: Gemfile.rails-4.0
|
11
30
|
env:
|
12
31
|
- DB=sqlite
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
## Next Release
|
2
2
|
|
3
|
+
## 6.0.1 (06/26/2019)
|
4
|
+
|
5
|
+
* Add Bullet::ActiveJob
|
6
|
+
* Prevent "Maximum call stack exceeded" errors when used with Turbolinks
|
7
|
+
|
8
|
+
## 6.0.0 (04/25/2019)
|
9
|
+
|
10
|
+
* Add XHR support to Bullet
|
11
|
+
* Support Rails 6.0
|
12
|
+
* Handle case where ID is manually set on unpersisted record
|
13
|
+
|
3
14
|
## 5.9.0 (11/11/2018)
|
4
15
|
|
5
16
|
* Require Ruby 2.3+
|
data/Gemfile.rails-4.0
CHANGED
@@ -3,7 +3,7 @@ source "https://rubygems.org"
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
gem 'rails', '~> 4.0.0'
|
6
|
-
gem 'sqlite3', platforms: [:ruby]
|
6
|
+
gem 'sqlite3', '~> 1.3.6', platforms: [:ruby]
|
7
7
|
gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
|
8
8
|
gem 'activerecord-import'
|
9
9
|
gem 'tins', '~> 1.6.0', platforms: [:ruby_19]
|
data/Gemfile.rails-4.1
CHANGED
data/Gemfile.rails-4.2
CHANGED
data/Gemfile.rails-5.0
CHANGED
data/Gemfile.rails-5.1
CHANGED
data/Gemfile.rails-5.2
CHANGED
data/Gemfile.rails-6.0
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
gem 'rails', '6.0.0.rc1'
|
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/README.md
CHANGED
@@ -181,15 +181,27 @@ If you find Bullet does not work for you, *please disable your browser's cache*.
|
|
181
181
|
|
182
182
|
## Advanced
|
183
183
|
|
184
|
-
###
|
184
|
+
### Work with ActiveJob
|
185
185
|
|
186
|
-
|
186
|
+
Include `Bullet::ActiveJob` in your `ApplicationJob`.
|
187
187
|
|
188
188
|
```ruby
|
189
|
-
|
190
|
-
|
189
|
+
class ApplicationJob < ActiveJob::Base
|
190
|
+
include Bullet::ActiveJob if Rails.env.development?
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
### Work with other background job solution
|
191
195
|
|
192
|
-
|
196
|
+
Use the Bullet.profile method.
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
class ApplicationJob < ActiveJob::Base
|
200
|
+
around_perform do |_job, block|
|
201
|
+
Bullet.profile do
|
202
|
+
block.call
|
203
|
+
end
|
204
|
+
end
|
193
205
|
end
|
194
206
|
```
|
195
207
|
|
@@ -221,7 +233,7 @@ end
|
|
221
233
|
Then wrap each test in Bullet api.
|
222
234
|
|
223
235
|
```ruby
|
224
|
-
# spec/
|
236
|
+
# spec/rails_helper.rb
|
225
237
|
if Bullet.enable?
|
226
238
|
config.before(:each) do
|
227
239
|
Bullet.start_request
|
@@ -458,4 +470,4 @@ Meanwhile, there's a line appended to `log/bullet.log`
|
|
458
470
|
Post => [:comments]
|
459
471
|
```
|
460
472
|
|
461
|
-
Copyright (c) 2009 -
|
473
|
+
Copyright (c) 2009 - 2019 Richard Huang (flyerhzm@gmail.com), released under the MIT license
|
data/lib/bullet.rb
CHANGED
@@ -14,6 +14,7 @@ module Bullet
|
|
14
14
|
autoload :ActiveRecord, "bullet/#{active_record_version}" if active_record?
|
15
15
|
autoload :Mongoid, "bullet/#{mongoid_version}" if mongoid?
|
16
16
|
autoload :Rack, 'bullet/rack'
|
17
|
+
autoload :ActiveJob, 'bullet/active_job'
|
17
18
|
autoload :Notification, 'bullet/notification'
|
18
19
|
autoload :Detector, 'bullet/detector'
|
19
20
|
autoload :Registry, 'bullet/registry'
|
@@ -63,6 +64,10 @@ module Bullet
|
|
63
64
|
!!@enable
|
64
65
|
end
|
65
66
|
|
67
|
+
def app_root
|
68
|
+
(defined?(::Rails.root) ? Rails.root.to_s : Dir.pwd).to_s
|
69
|
+
end
|
70
|
+
|
66
71
|
def n_plus_one_query_enable?
|
67
72
|
enable? && !!@n_plus_one_query_enable
|
68
73
|
end
|
@@ -111,9 +116,8 @@ module Bullet
|
|
111
116
|
def bullet_logger=(active)
|
112
117
|
if active
|
113
118
|
require 'fileutils'
|
114
|
-
|
115
|
-
|
116
|
-
bullet_log_file = File.open("#{root_path}/log/bullet.log", 'a+')
|
119
|
+
FileUtils.mkdir_p(app_root + '/log')
|
120
|
+
bullet_log_file = File.open("#{app_root}/log/bullet.log", 'a+')
|
117
121
|
bullet_log_file.sync = true
|
118
122
|
UniformNotifier.customized_logger = bullet_log_file
|
119
123
|
end
|
@@ -192,6 +196,14 @@ module Bullet
|
|
192
196
|
info
|
193
197
|
end
|
194
198
|
|
199
|
+
def text_notifications
|
200
|
+
info = []
|
201
|
+
notification_collector.collection.each do |notification|
|
202
|
+
info << notification.notification_data.values.compact.join("\n")
|
203
|
+
end
|
204
|
+
info
|
205
|
+
end
|
206
|
+
|
195
207
|
def warnings
|
196
208
|
notification_collector.collection.each_with_object({}) do |notification, warnings|
|
197
209
|
warning_type = notification.class.to_s.split(':').last.tableize
|
@@ -219,6 +231,10 @@ module Bullet
|
|
219
231
|
return_value
|
220
232
|
end
|
221
233
|
|
234
|
+
def console_enabled?
|
235
|
+
UniformNotifier.active_notifiers.include?(UniformNotifier::JavascriptConsole)
|
236
|
+
end
|
237
|
+
|
222
238
|
private
|
223
239
|
|
224
240
|
def for_each_active_notifier_with_notification
|
@@ -181,7 +181,6 @@ module Bullet
|
|
181
181
|
::ActiveRecord::Associations::HasManyAssociation.class_eval do
|
182
182
|
alias_method :origin_has_cached_counter?, :has_cached_counter?
|
183
183
|
|
184
|
-
# rubocop:disable Style/MethodCallWithoutArgsParentheses
|
185
184
|
def has_cached_counter?(reflection = reflection())
|
186
185
|
result = origin_has_cached_counter?(reflection)
|
187
186
|
if Bullet.start? && !result
|
@@ -189,15 +188,7 @@ module Bullet
|
|
189
188
|
end
|
190
189
|
result
|
191
190
|
end
|
192
|
-
|
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
|
191
|
+
|
201
192
|
end
|
202
193
|
end
|
203
194
|
end
|
@@ -179,14 +179,6 @@ module Bullet
|
|
179
179
|
origin_count_records
|
180
180
|
end
|
181
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
|
190
182
|
end
|
191
183
|
end
|
192
184
|
end
|
@@ -240,14 +240,6 @@ module Bullet
|
|
240
240
|
origin_count_records
|
241
241
|
end
|
242
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
|
251
243
|
end
|
252
244
|
end
|
253
245
|
end
|
@@ -171,9 +171,7 @@ module Bullet
|
|
171
171
|
end
|
172
172
|
|
173
173
|
if refl.through_reflection?
|
174
|
-
while refl.through_reflection?
|
175
|
-
refl = refl.through_reflection
|
176
|
-
end
|
174
|
+
refl = refl.through_reflection while refl.through_reflection?
|
177
175
|
|
178
176
|
Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
|
179
177
|
end
|
@@ -242,13 +240,6 @@ module Bullet
|
|
242
240
|
super
|
243
241
|
end
|
244
242
|
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)
|
252
243
|
end
|
253
244
|
end
|
254
245
|
end
|
@@ -220,13 +220,6 @@ module Bullet
|
|
220
220
|
super
|
221
221
|
end
|
222
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)
|
230
223
|
end
|
231
224
|
end
|
232
225
|
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bullet
|
4
|
+
module SaveWithBulletSupport
|
5
|
+
def _create_record(*)
|
6
|
+
super do
|
7
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
|
8
|
+
yield(self) if block_given?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ActiveRecord
|
14
|
+
def self.enable
|
15
|
+
require 'active_record'
|
16
|
+
::ActiveRecord::Base.extend(Module.new do
|
17
|
+
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
18
|
+
result = super
|
19
|
+
if Bullet.start?
|
20
|
+
if result.is_a? Array
|
21
|
+
if result.size > 1
|
22
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
23
|
+
Bullet::Detector::CounterCache.add_possible_objects(result)
|
24
|
+
elsif result.size == 1
|
25
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
|
26
|
+
Bullet::Detector::CounterCache.add_impossible_object(result.first)
|
27
|
+
end
|
28
|
+
elsif result.is_a? ::ActiveRecord::Base
|
29
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
|
30
|
+
Bullet::Detector::CounterCache.add_impossible_object(result)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
result
|
34
|
+
end
|
35
|
+
end)
|
36
|
+
|
37
|
+
::ActiveRecord::Base.prepend(SaveWithBulletSupport)
|
38
|
+
|
39
|
+
::ActiveRecord::Relation.prepend(Module.new do
|
40
|
+
# if select a collection of objects, then these objects have possible to cause N+1 query.
|
41
|
+
# if select only one object, then the only one object has impossible to cause N+1 query.
|
42
|
+
def records
|
43
|
+
result = super
|
44
|
+
if Bullet.start?
|
45
|
+
if result.first.class.name !~ /^HABTM_/
|
46
|
+
if result.size > 1
|
47
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
|
48
|
+
Bullet::Detector::CounterCache.add_possible_objects(result)
|
49
|
+
elsif result.size == 1
|
50
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
|
51
|
+
Bullet::Detector::CounterCache.add_impossible_object(result.first)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end)
|
58
|
+
|
59
|
+
::ActiveRecord::Associations::Preloader.prepend(Module.new do
|
60
|
+
def preloaders_for_one(association, records, scope, polymorphic_parent)
|
61
|
+
if Bullet.start?
|
62
|
+
records.compact!
|
63
|
+
if records.first.class.name !~ /^HABTM_/
|
64
|
+
records.each do |record|
|
65
|
+
Bullet::Detector::Association.add_object_associations(record, association)
|
66
|
+
end
|
67
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
super
|
71
|
+
end
|
72
|
+
|
73
|
+
def preloaders_for_reflection(reflection, records, scope)
|
74
|
+
if Bullet.start?
|
75
|
+
records.compact!
|
76
|
+
if records.first.class.name !~ /^HABTM_/
|
77
|
+
records.each do |record|
|
78
|
+
Bullet::Detector::Association.add_object_associations(record, reflection.name)
|
79
|
+
end
|
80
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, reflection.name)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end)
|
86
|
+
|
87
|
+
::ActiveRecord::FinderMethods.prepend(Module.new do
|
88
|
+
# add includes in scope
|
89
|
+
def find_with_associations
|
90
|
+
return super { |r| yield r } if block_given?
|
91
|
+
|
92
|
+
records = super
|
93
|
+
if Bullet.start?
|
94
|
+
associations = (eager_load_values + includes_values).uniq
|
95
|
+
records.each do |record|
|
96
|
+
Bullet::Detector::Association.add_object_associations(record, associations)
|
97
|
+
end
|
98
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
|
99
|
+
end
|
100
|
+
records
|
101
|
+
end
|
102
|
+
end)
|
103
|
+
|
104
|
+
::ActiveRecord::Associations::JoinDependency.prepend(Module.new do
|
105
|
+
def instantiate(result_set, &block)
|
106
|
+
@bullet_eager_loadings = {}
|
107
|
+
records = super
|
108
|
+
|
109
|
+
if Bullet.start?
|
110
|
+
@bullet_eager_loadings.each do |_klazz, eager_loadings_hash|
|
111
|
+
objects = eager_loadings_hash.keys
|
112
|
+
Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
records
|
116
|
+
end
|
117
|
+
|
118
|
+
def construct(ar_parent, parent, row, seen, model_cache)
|
119
|
+
if Bullet.start?
|
120
|
+
unless ar_parent.nil?
|
121
|
+
parent.children.each do |node|
|
122
|
+
key = aliases.column_alias(node, node.primary_key)
|
123
|
+
id = row[key]
|
124
|
+
next unless id.nil?
|
125
|
+
|
126
|
+
associations = node.reflection.name
|
127
|
+
Bullet::Detector::Association.add_object_associations(ar_parent, associations)
|
128
|
+
Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
|
129
|
+
@bullet_eager_loadings[ar_parent.class] ||= {}
|
130
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] ||= Set.new
|
131
|
+
@bullet_eager_loadings[ar_parent.class][ar_parent] << associations
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
super
|
137
|
+
end
|
138
|
+
|
139
|
+
# call join associations
|
140
|
+
def construct_model(record, node, row, model_cache, id)
|
141
|
+
result = super
|
142
|
+
|
143
|
+
if Bullet.start?
|
144
|
+
associations = node.reflection.name
|
145
|
+
Bullet::Detector::Association.add_object_associations(record, associations)
|
146
|
+
Bullet::Detector::NPlusOneQuery.call_association(record, associations)
|
147
|
+
@bullet_eager_loadings[record.class] ||= {}
|
148
|
+
@bullet_eager_loadings[record.class][record] ||= Set.new
|
149
|
+
@bullet_eager_loadings[record.class][record] << associations
|
150
|
+
end
|
151
|
+
|
152
|
+
result
|
153
|
+
end
|
154
|
+
end)
|
155
|
+
|
156
|
+
::ActiveRecord::Associations::CollectionAssociation.prepend(Module.new do
|
157
|
+
def load_target
|
158
|
+
records = super
|
159
|
+
|
160
|
+
if Bullet.start?
|
161
|
+
if is_a? ::ActiveRecord::Associations::ThroughAssociation
|
162
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
|
163
|
+
association = owner.association reflection.through_reflection.name
|
164
|
+
Array(association.target).each do |through_record|
|
165
|
+
Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
|
166
|
+
end
|
167
|
+
|
168
|
+
if reflection.through_reflection != through_reflection
|
169
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
|
173
|
+
if records.first.class.name !~ /^HABTM_/
|
174
|
+
if records.size > 1
|
175
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
|
176
|
+
Bullet::Detector::CounterCache.add_possible_objects(records)
|
177
|
+
elsif records.size == 1
|
178
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
|
179
|
+
Bullet::Detector::CounterCache.add_impossible_object(records.first)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
records
|
184
|
+
end
|
185
|
+
|
186
|
+
def empty?
|
187
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
188
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
189
|
+
end
|
190
|
+
super
|
191
|
+
end
|
192
|
+
|
193
|
+
def include?(object)
|
194
|
+
if Bullet.start?
|
195
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
196
|
+
end
|
197
|
+
super
|
198
|
+
end
|
199
|
+
end)
|
200
|
+
|
201
|
+
::ActiveRecord::Associations::SingularAssociation.prepend(Module.new do
|
202
|
+
# call has_one and belongs_to associations
|
203
|
+
def target
|
204
|
+
result = super()
|
205
|
+
if Bullet.start?
|
206
|
+
if owner.class.name !~ /^HABTM_/ && !@inversed
|
207
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
208
|
+
if Bullet::Detector::NPlusOneQuery.impossible?(owner)
|
209
|
+
Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
|
210
|
+
else
|
211
|
+
Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
result
|
216
|
+
end
|
217
|
+
end)
|
218
|
+
|
219
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(Module.new do
|
220
|
+
def empty?
|
221
|
+
result = super
|
222
|
+
if Bullet.start? && !reflection.has_cached_counter?
|
223
|
+
Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
|
224
|
+
end
|
225
|
+
result
|
226
|
+
end
|
227
|
+
|
228
|
+
def count_records
|
229
|
+
result = reflection.has_cached_counter?
|
230
|
+
if Bullet.start? && !result && !is_a?(::ActiveRecord::Associations::ThroughAssociation)
|
231
|
+
Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
|
232
|
+
end
|
233
|
+
super
|
234
|
+
end
|
235
|
+
end)
|
236
|
+
|
237
|
+
::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
|
238
|
+
def writer(record)
|
239
|
+
Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
|
240
|
+
super
|
241
|
+
end
|
242
|
+
end)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
(function() {
|
2
|
+
var oldOpen = window.XMLHttpRequest.prototype.open;
|
3
|
+
var oldSend = window.XMLHttpRequest.prototype.send;
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Return early if we've already extended prototype. This prevents
|
7
|
+
* "maximum call stack exceeded" errors when used with Turbolinks.
|
8
|
+
* See https://github.com/flyerhzm/bullet/issues/454
|
9
|
+
*/
|
10
|
+
if (isBulletInitiated()) return;
|
11
|
+
|
12
|
+
function isBulletInitiated() {
|
13
|
+
return oldOpen.name == 'bulletXHROpen' && oldSend.name == 'bulletXHRSend';
|
14
|
+
}
|
15
|
+
function bulletXHROpen(_, url) {
|
16
|
+
this._storedUrl = url;
|
17
|
+
return oldOpen.apply(this, arguments);
|
18
|
+
}
|
19
|
+
function bulletXHRSend() {
|
20
|
+
if (this.onload) {
|
21
|
+
this._storedOnload = this.onload;
|
22
|
+
}
|
23
|
+
this.addEventListener('load', bulletXHROnload);
|
24
|
+
return oldSend.apply(this, arguments);
|
25
|
+
}
|
26
|
+
function bulletXHROnload() {
|
27
|
+
if (
|
28
|
+
this._storedUrl.startsWith(
|
29
|
+
window.location.protocol + '//' + window.location.host
|
30
|
+
) ||
|
31
|
+
!this._storedUrl.startsWith('http') // For relative paths
|
32
|
+
) {
|
33
|
+
var bulletFooterText = this.getResponseHeader('X-bullet-footer-text');
|
34
|
+
if (bulletFooterText) {
|
35
|
+
setTimeout(() => {
|
36
|
+
var oldHtml = document
|
37
|
+
.getElementById('bullet-footer')
|
38
|
+
.innerHTML.split('<br>');
|
39
|
+
var header = oldHtml[0];
|
40
|
+
oldHtml = oldHtml.slice(1, oldHtml.length);
|
41
|
+
var newHtml = oldHtml.concat(JSON.parse(bulletFooterText));
|
42
|
+
newHtml = newHtml.slice(newHtml.length - 10, newHtml.length); // rotate through 10 most recent
|
43
|
+
document.getElementById(
|
44
|
+
'bullet-footer'
|
45
|
+
).innerHTML = `${header}<br>${newHtml.join('<br>')}`;
|
46
|
+
}, 0);
|
47
|
+
}
|
48
|
+
var bulletConsoleText = this.getResponseHeader('X-bullet-console-text');
|
49
|
+
if (bulletConsoleText && typeof console !== 'undefined' && console.log) {
|
50
|
+
setTimeout(() => {
|
51
|
+
JSON.parse(bulletConsoleText).forEach(message => {
|
52
|
+
if (console.groupCollapsed && console.groupEnd) {
|
53
|
+
console.groupCollapsed('Uniform Notifier');
|
54
|
+
console.log(message);
|
55
|
+
console.groupEnd();
|
56
|
+
} else {
|
57
|
+
console.log(message);
|
58
|
+
}
|
59
|
+
});
|
60
|
+
}, 0);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
if (this._storedOnload) {
|
64
|
+
return this._storedOnload.apply(this, arguments);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
window.XMLHttpRequest.prototype.open = bulletXHROpen;
|
68
|
+
window.XMLHttpRequest.prototype.send = bulletXHRSend;
|
69
|
+
})();
|
data/lib/bullet/dependency.rb
CHANGED
@@ -10,10 +10,6 @@ module Bullet
|
|
10
10
|
@active_record ||= defined? ::ActiveRecord
|
11
11
|
end
|
12
12
|
|
13
|
-
def rails?
|
14
|
-
@rails ||= defined? ::Rails
|
15
|
-
end
|
16
|
-
|
17
13
|
def active_record_version
|
18
14
|
@active_record_version ||= begin
|
19
15
|
if active_record40?
|
@@ -28,6 +24,8 @@ module Bullet
|
|
28
24
|
'active_record5'
|
29
25
|
elsif active_record52?
|
30
26
|
'active_record52'
|
27
|
+
elsif active_record60?
|
28
|
+
'active_record60'
|
31
29
|
else
|
32
30
|
raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
|
33
31
|
end
|
@@ -58,6 +56,10 @@ module Bullet
|
|
58
56
|
active_record? && ::ActiveRecord::VERSION::MAJOR == 5
|
59
57
|
end
|
60
58
|
|
59
|
+
def active_record6?
|
60
|
+
active_record? && ::ActiveRecord::VERSION::MAJOR == 6
|
61
|
+
end
|
62
|
+
|
61
63
|
def active_record40?
|
62
64
|
active_record4? && ::ActiveRecord::VERSION::MINOR == 0
|
63
65
|
end
|
@@ -82,6 +84,10 @@ module Bullet
|
|
82
84
|
active_record5? && ::ActiveRecord::VERSION::MINOR == 2
|
83
85
|
end
|
84
86
|
|
87
|
+
def active_record60?
|
88
|
+
active_record6? && ::ActiveRecord::VERSION::MINOR == 0
|
89
|
+
end
|
90
|
+
|
85
91
|
def mongoid4x?
|
86
92
|
mongoid? && ::Mongoid::VERSION =~ /\A4/
|
87
93
|
end
|
@@ -7,7 +7,7 @@ module Bullet
|
|
7
7
|
def add_object_associations(object, associations)
|
8
8
|
return unless Bullet.start?
|
9
9
|
return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
|
10
|
-
return unless object.
|
10
|
+
return unless object.bullet_primary_key_value
|
11
11
|
|
12
12
|
Bullet.debug('Detector::Association#add_object_associations', "object: #{object.bullet_key}, associations: #{associations}")
|
13
13
|
object_associations.add(object.bullet_key, associations)
|
@@ -16,7 +16,7 @@ module Bullet
|
|
16
16
|
def add_call_object_associations(object, associations)
|
17
17
|
return unless Bullet.start?
|
18
18
|
return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
|
19
|
-
return unless object.
|
19
|
+
return unless object.bullet_primary_key_value
|
20
20
|
|
21
21
|
Bullet.debug('Detector::Association#add_call_object_associations', "object: #{object.bullet_key}, associations: #{associations}")
|
22
22
|
call_object_associations.add(object.bullet_key, associations)
|
@@ -7,7 +7,7 @@ module Bullet
|
|
7
7
|
def add_counter_cache(object, associations)
|
8
8
|
return unless Bullet.start?
|
9
9
|
return unless Bullet.counter_cache_enable?
|
10
|
-
return unless object.
|
10
|
+
return unless object.bullet_primary_key_value
|
11
11
|
|
12
12
|
Bullet.debug('Detector::CounterCache#add_counter_cache', "object: #{object.bullet_key}, associations: #{associations}")
|
13
13
|
if conditions_met?(object, associations)
|
@@ -20,7 +20,7 @@ module Bullet
|
|
20
20
|
return unless Bullet.counter_cache_enable?
|
21
21
|
|
22
22
|
objects = Array(object_or_objects)
|
23
|
-
return if objects.map(&:
|
23
|
+
return if objects.map(&:bullet_primary_key_value).compact.empty?
|
24
24
|
|
25
25
|
Bullet.debug('Detector::CounterCache#add_possible_objects', "objects: #{objects.map(&:bullet_key).join(', ')}")
|
26
26
|
objects.each { |object| possible_objects.add object.bullet_key }
|
@@ -29,7 +29,7 @@ module Bullet
|
|
29
29
|
def add_impossible_object(object)
|
30
30
|
return unless Bullet.start?
|
31
31
|
return unless Bullet.counter_cache_enable?
|
32
|
-
return unless object.
|
32
|
+
return unless object.bullet_primary_key_value
|
33
33
|
|
34
34
|
Bullet.debug('Detector::CounterCache#add_impossible_object', "object: #{object.bullet_key}")
|
35
35
|
impossible_objects.add object.bullet_key
|
@@ -14,7 +14,7 @@ module Bullet
|
|
14
14
|
def call_association(object, associations)
|
15
15
|
return unless Bullet.start?
|
16
16
|
return unless Bullet.n_plus_one_query_enable?
|
17
|
-
return unless object.
|
17
|
+
return unless object.bullet_primary_key_value
|
18
18
|
return if inversed_objects.include?(object.bullet_key, associations)
|
19
19
|
|
20
20
|
add_call_object_associations(object, associations)
|
@@ -31,7 +31,7 @@ module Bullet
|
|
31
31
|
return unless Bullet.n_plus_one_query_enable?
|
32
32
|
|
33
33
|
objects = Array(object_or_objects)
|
34
|
-
return if objects.map(&:
|
34
|
+
return if objects.map(&:bullet_primary_key_value).compact.empty?
|
35
35
|
|
36
36
|
Bullet.debug('Detector::NPlusOneQuery#add_possible_objects', "objects: #{objects.map(&:bullet_key).join(', ')}")
|
37
37
|
objects.each { |object| possible_objects.add object.bullet_key }
|
@@ -40,7 +40,7 @@ module Bullet
|
|
40
40
|
def add_impossible_object(object)
|
41
41
|
return unless Bullet.start?
|
42
42
|
return unless Bullet.n_plus_one_query_enable?
|
43
|
-
return unless object.
|
43
|
+
return unless object.bullet_primary_key_value
|
44
44
|
|
45
45
|
Bullet.debug('Detector::NPlusOneQuery#add_impossible_object', "object: #{object.bullet_key}")
|
46
46
|
impossible_objects.add object.bullet_key
|
@@ -49,7 +49,7 @@ module Bullet
|
|
49
49
|
def add_inversed_object(object, association)
|
50
50
|
return unless Bullet.start?
|
51
51
|
return unless Bullet.n_plus_one_query_enable?
|
52
|
-
return unless object.
|
52
|
+
return unless object.bullet_primary_key_value
|
53
53
|
|
54
54
|
Bullet.debug('Detector::NPlusOneQuery#add_inversed_object', "object: #{object.bullet_key}, association: #{association}")
|
55
55
|
inversed_objects.add object.bullet_key, association
|
@@ -27,7 +27,7 @@ module Bullet
|
|
27
27
|
def add_eager_loadings(objects, associations)
|
28
28
|
return unless Bullet.start?
|
29
29
|
return unless Bullet.unused_eager_loading_enable?
|
30
|
-
return if objects.map(&:
|
30
|
+
return if objects.map(&:bullet_primary_key_value).compact.empty?
|
31
31
|
|
32
32
|
Bullet.debug('Detector::UnusedEagerLoading#add_eager_loadings', "objects: #{objects.map(&:bullet_key).join(', ')}, associations: #{associations}")
|
33
33
|
bullet_keys = objects.map(&:bullet_key)
|
data/lib/bullet/ext/object.rb
CHANGED
@@ -2,10 +2,12 @@
|
|
2
2
|
|
3
3
|
class Object
|
4
4
|
def bullet_key
|
5
|
-
"#{self.class}:#{
|
5
|
+
"#{self.class}:#{bullet_primary_key_value}"
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
8
|
+
def bullet_primary_key_value
|
9
|
+
return if respond_to?(:persisted?) && !persisted?
|
10
|
+
|
9
11
|
if self.class.respond_to?(:primary_keys) && self.class.primary_keys
|
10
12
|
self.class.primary_keys.map { |primary_key| send primary_key }.join(',')
|
11
13
|
elsif self.class.respond_to?(:primary_key) && self.class.primary_key
|
data/lib/bullet/rack.rb
CHANGED
@@ -16,12 +16,17 @@ module Bullet
|
|
16
16
|
|
17
17
|
response_body = nil
|
18
18
|
if Bullet.notification?
|
19
|
-
if !file?(headers) && !sse?(headers) && !empty?(response) &&
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
if !file?(headers) && !sse?(headers) && !empty?(response) && status == 200
|
20
|
+
if html_request?(headers, response)
|
21
|
+
response_body = response_body(response)
|
22
|
+
response_body = append_to_html_body(response_body, footer_note) if Bullet.add_footer
|
23
|
+
response_body = append_to_html_body(response_body, Bullet.gather_inline_notifications)
|
24
|
+
response_body = append_to_html_body(response_body, xhr_script)
|
25
|
+
headers['Content-Length'] = response_body.bytesize.to_s
|
26
|
+
else
|
27
|
+
set_header(headers, 'X-bullet-footer-text', Bullet.footer_info.uniq) if Bullet.add_footer
|
28
|
+
set_header(headers, 'X-bullet-console-text', Bullet.text_notifications) if Bullet.console_enabled?
|
29
|
+
end
|
25
30
|
end
|
26
31
|
Bullet.perform_out_of_channel_notifications(env)
|
27
32
|
end
|
@@ -32,16 +37,10 @@ module Bullet
|
|
32
37
|
|
33
38
|
# fix issue if response's body is a Proc
|
34
39
|
def empty?(response)
|
35
|
-
# response may be ["Not Found"], ["Move Permanently"], etc
|
36
|
-
if
|
37
|
-
|
38
|
-
|
39
|
-
!response_body(response).respond_to?(:empty?) ||
|
40
|
-
response_body(response).empty?
|
41
|
-
else
|
42
|
-
body = response_body(response)
|
43
|
-
body.nil? || body.empty?
|
44
|
-
end
|
40
|
+
# response may be ["Not Found"], ["Move Permanently"], etc, but
|
41
|
+
# those should not happen if the status is 200
|
42
|
+
body = response_body(response)
|
43
|
+
body.nil? || body.empty?
|
45
44
|
end
|
46
45
|
|
47
46
|
def append_to_html_body(response_body, content)
|
@@ -55,7 +54,15 @@ module Bullet
|
|
55
54
|
end
|
56
55
|
|
57
56
|
def footer_note
|
58
|
-
"<div #{footer_div_attributes}>" +
|
57
|
+
"<div #{footer_div_attributes}>" + footer_header + '<br>' + Bullet.footer_info.uniq.join('<br>') + '</div>'
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_header(headers, header_name, header_array)
|
61
|
+
# Many proxy applications such as Nginx and AWS ELB limit
|
62
|
+
# the size a header to 8KB, so truncate the list of reports to
|
63
|
+
# be under that limit
|
64
|
+
header_array.pop while header_array.to_json.length > 8 * 1024
|
65
|
+
headers[header_name] = header_array.to_json
|
59
66
|
end
|
60
67
|
|
61
68
|
def file?(headers)
|
@@ -82,7 +89,7 @@ module Bullet
|
|
82
89
|
|
83
90
|
def footer_div_attributes
|
84
91
|
<<~EOF
|
85
|
-
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);
|
92
|
+
id="bullet-footer" 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);
|
86
93
|
-moz-border-top-colors: none; -moz-border-right-colors: none; -moz-border-bottom-colors: none;
|
87
94
|
-moz-border-left-colors: none; -moz-border-image: none; border-width: 2pt 2pt 0px 0px;
|
88
95
|
padding: 3px 5px; border-radius: 0pt 10pt 0pt 0px; background: none repeat scroll 0% 0% rgba(200, 200, 200, 0.8);
|
@@ -90,8 +97,18 @@ module Bullet
|
|
90
97
|
EOF
|
91
98
|
end
|
92
99
|
|
93
|
-
def
|
94
|
-
"<span onclick='this.parentNode.remove()' style='position:absolute; right: 10px; top: 0px; font-weight: bold; color: #333;'>×</span>"
|
100
|
+
def footer_header
|
101
|
+
cancel_button = "<span onclick='this.parentNode.remove()' style='position:absolute; right: 10px; top: 0px; font-weight: bold; color: #333;'>×</span>"
|
102
|
+
if Bullet.console_enabled?
|
103
|
+
"<span>See 'Uniform Notifier' in JS Console for Stacktrace</span>#{cancel_button}"
|
104
|
+
else
|
105
|
+
cancel_button
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Make footer work for XHR requests by appending data to the footer
|
110
|
+
def xhr_script
|
111
|
+
"<script type='text/javascript'>#{File.read("#{__dir__}/bullet_xhr.js")}</script>"
|
95
112
|
end
|
96
113
|
end
|
97
114
|
end
|
@@ -5,12 +5,11 @@ module Bullet
|
|
5
5
|
VENDOR_PATH = '/vendor'
|
6
6
|
|
7
7
|
def caller_in_project
|
8
|
-
|
9
|
-
vendor_root = app_root + VENDOR_PATH
|
8
|
+
vendor_root = Bullet.app_root + VENDOR_PATH
|
10
9
|
bundler_path = Bundler.bundle_path.to_s
|
11
10
|
select_caller_locations do |location|
|
12
11
|
caller_path = location_as_path(location)
|
13
|
-
caller_path.include?(app_root) && !caller_path.include?(vendor_root) && !caller_path.include?(bundler_path) ||
|
12
|
+
caller_path.include?(Bullet.app_root) && !caller_path.include?(vendor_root) && !caller_path.include?(bundler_path) ||
|
14
13
|
Bullet.stacktrace_includes.any? { |include_pattern| pattern_matches?(location, include_pattern) }
|
15
14
|
end
|
16
15
|
end
|
data/lib/bullet/version.rb
CHANGED
@@ -17,23 +17,28 @@ describe Object do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
context '
|
20
|
+
context 'bullet_primary_key_value' do
|
21
21
|
it 'should return id' do
|
22
22
|
post = Post.first
|
23
|
-
expect(post.
|
23
|
+
expect(post.bullet_primary_key_value).to eq(post.id)
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'should return primary key value' do
|
27
27
|
post = Post.first
|
28
28
|
Post.primary_key = 'name'
|
29
|
-
expect(post.
|
29
|
+
expect(post.bullet_primary_key_value).to eq(post.name)
|
30
30
|
Post.primary_key = 'id'
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'should return value for multiple primary keys' do
|
34
34
|
post = Post.first
|
35
35
|
allow(Post).to receive(:primary_keys).and_return(%i[category_id writer_id])
|
36
|
-
expect(post.
|
36
|
+
expect(post.bullet_primary_key_value).to eq("#{post.category_id},#{post.writer_id}")
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'it should return nil for unpersisted records' do
|
40
|
+
post = Post.new(id: 123)
|
41
|
+
expect(post.bullet_primary_key_value).to be_nil
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
data/spec/bullet/rack_spec.rb
CHANGED
@@ -45,9 +45,9 @@ module Bullet
|
|
45
45
|
expect(middleware).not_to be_empty(response)
|
46
46
|
end
|
47
47
|
|
48
|
-
it 'should be
|
48
|
+
it 'should be false if response is not found' do
|
49
49
|
response = ['Not Found']
|
50
|
-
expect(middleware).
|
50
|
+
expect(middleware).not_to be_empty(response)
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'should be true if response body is empty' do
|
@@ -68,6 +68,7 @@ module Bullet
|
|
68
68
|
it 'should change response body if notification is active' do
|
69
69
|
expect(Bullet).to receive(:notification?).and_return(true)
|
70
70
|
expect(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
|
71
|
+
expect(middleware).to receive(:xhr_script).and_return('')
|
71
72
|
expect(Bullet).to receive(:perform_out_of_channel_notifications)
|
72
73
|
status, headers, response = middleware.call('Content-Type' => 'text/html')
|
73
74
|
expect(headers['Content-Length']).to eq('56')
|
@@ -81,7 +82,7 @@ module Bullet
|
|
81
82
|
expect(Bullet).to receive(:notification?).and_return(true)
|
82
83
|
expect(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
|
83
84
|
status, headers, response = middleware.call('Content-Type' => 'text/html')
|
84
|
-
expect(headers['Content-Length']).to eq(
|
85
|
+
expect(headers['Content-Length']).to eq((58 + middleware.send(:xhr_script).length).to_s)
|
85
86
|
end
|
86
87
|
end
|
87
88
|
|
@@ -95,6 +96,14 @@ module Bullet
|
|
95
96
|
end
|
96
97
|
end
|
97
98
|
|
99
|
+
context '#set_header' do
|
100
|
+
it 'should truncate headers to under 8kb' do
|
101
|
+
long_header = ['a' * 1024] * 10
|
102
|
+
expected_res = (['a' * 1024] * 7).to_json
|
103
|
+
expect(middleware.set_header({}, 'Dummy-Header', long_header)).to eq(expected_res)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
98
107
|
describe '#response_body' do
|
99
108
|
let(:response) { double }
|
100
109
|
let(:body_string) { '<html><body>My Body</body></html>' }
|
@@ -246,7 +246,7 @@ if active_record?
|
|
246
246
|
category = Category.first
|
247
247
|
category.draft_post.destroy!
|
248
248
|
post = category.draft_post
|
249
|
-
post.
|
249
|
+
post.update!(link: true)
|
250
250
|
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
251
251
|
expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
|
252
252
|
|
@@ -331,7 +331,7 @@ if active_record?
|
|
331
331
|
expect(Bullet::Detector::Association).to be_completely_preloading_associations
|
332
332
|
end
|
333
333
|
|
334
|
-
it 'should
|
334
|
+
it 'should detect preload with comment => post' do
|
335
335
|
Comment.includes(:post).each do |comment|
|
336
336
|
comment.post.name
|
337
337
|
end
|
@@ -362,22 +362,11 @@ if active_record?
|
|
362
362
|
|
363
363
|
new_post.trigger_after_save = true
|
364
364
|
new_post.save!
|
365
|
+
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
365
366
|
expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
|
366
367
|
|
367
368
|
expect(Bullet::Detector::Association).to be_completely_preloading_associations
|
368
369
|
end
|
369
|
-
|
370
|
-
it 'should not detect "manual" preload' do
|
371
|
-
comment = Comment.all.to_a.first
|
372
|
-
post = Post.find(comment.post_id)
|
373
|
-
# "manually" preload with out-of-band data
|
374
|
-
comment.post = post
|
375
|
-
# loading it should not trigger anything
|
376
|
-
comment.post
|
377
|
-
|
378
|
-
expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
|
379
|
-
expect(Bullet::Detector::Association).to be_completely_preloading_associations
|
380
|
-
end
|
381
370
|
end
|
382
371
|
|
383
372
|
context 'comment => post => category' do
|
@@ -38,7 +38,7 @@ if !mongoid? && active_record?
|
|
38
38
|
expect(Bullet.collected_counter_cache_notifications).to be_empty
|
39
39
|
end
|
40
40
|
|
41
|
-
if active_record5?
|
41
|
+
if active_record5? || active_record6?
|
42
42
|
it 'should not need counter cache for has_many through' do
|
43
43
|
Client.all.each do |client|
|
44
44
|
client.firms.size
|
data/test.sh
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#bundle update rails && bundle exec rspec spec
|
2
2
|
#BUNDLE_GEMFILE=Gemfile.mongoid bundle update mongoid && BUNDLE_GEMFILE=Gemfile.mongoid bundle exec rspec spec
|
3
|
+
BUNDLE_GEMFILE=Gemfile.rails-6.0 bundle && BUNDLE_GEMFILE=Gemfile.rails-6.0 bundle exec rspec spec
|
3
4
|
BUNDLE_GEMFILE=Gemfile.rails-5.2 bundle && BUNDLE_GEMFILE=Gemfile.rails-5.2 bundle exec rspec spec
|
4
5
|
BUNDLE_GEMFILE=Gemfile.rails-5.1 bundle && BUNDLE_GEMFILE=Gemfile.rails-5.1 bundle exec rspec spec
|
5
6
|
BUNDLE_GEMFILE=Gemfile.rails-5.0 bundle && BUNDLE_GEMFILE=Gemfile.rails-5.0 bundle exec rspec spec
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 6.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -61,6 +61,7 @@ files:
|
|
61
61
|
- Gemfile.rails-5.0
|
62
62
|
- Gemfile.rails-5.1
|
63
63
|
- Gemfile.rails-5.2
|
64
|
+
- Gemfile.rails-6.0
|
64
65
|
- Guardfile
|
65
66
|
- Hacking.md
|
66
67
|
- MIT-LICENSE
|
@@ -68,11 +69,14 @@ files:
|
|
68
69
|
- Rakefile
|
69
70
|
- bullet.gemspec
|
70
71
|
- lib/bullet.rb
|
72
|
+
- lib/bullet/active_job.rb
|
71
73
|
- lib/bullet/active_record4.rb
|
72
74
|
- lib/bullet/active_record41.rb
|
73
75
|
- lib/bullet/active_record42.rb
|
74
76
|
- lib/bullet/active_record5.rb
|
75
77
|
- lib/bullet/active_record52.rb
|
78
|
+
- lib/bullet/active_record60.rb
|
79
|
+
- lib/bullet/bullet_xhr.js
|
76
80
|
- lib/bullet/dependency.rb
|
77
81
|
- lib/bullet/detector.rb
|
78
82
|
- lib/bullet/detector/association.rb
|
@@ -184,8 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
188
|
- !ruby/object:Gem::Version
|
185
189
|
version: 1.3.6
|
186
190
|
requirements: []
|
187
|
-
|
188
|
-
rubygems_version: 2.6.14
|
191
|
+
rubygems_version: 3.0.3
|
189
192
|
signing_key:
|
190
193
|
specification_version: 4
|
191
194
|
summary: help to kill N+1 queries and unused eager loading.
|