bullet 5.5.0 → 6.1.5
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/.github/workflows/main.yml +66 -0
- data/CHANGELOG.md +83 -1
- data/Gemfile +6 -1
- data/Gemfile.mongoid-7.0 +15 -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 +2 -2
- data/Gemfile.rails-5.1 +15 -0
- data/Gemfile.rails-5.2 +15 -0
- data/Gemfile.rails-6.0 +15 -0
- data/Gemfile.rails-6.1 +15 -0
- data/Guardfile +2 -2
- data/Hacking.md +1 -1
- data/README.md +58 -37
- data/Rakefile +20 -21
- data/bullet.gemspec +21 -15
- data/lib/bullet/active_job.rb +13 -0
- data/lib/bullet/active_record4.rb +15 -34
- data/lib/bullet/active_record41.rb +14 -31
- data/lib/bullet/active_record42.rb +23 -36
- data/lib/bullet/active_record5.rb +178 -158
- data/lib/bullet/active_record52.rb +251 -0
- data/lib/bullet/active_record60.rb +278 -0
- data/lib/bullet/active_record61.rb +278 -0
- data/lib/bullet/bullet_xhr.js +64 -0
- data/lib/bullet/dependency.rb +60 -32
- data/lib/bullet/detector/association.rb +41 -32
- data/lib/bullet/detector/base.rb +2 -0
- data/lib/bullet/detector/counter_cache.rb +25 -17
- data/lib/bullet/detector/n_plus_one_query.rb +38 -24
- data/lib/bullet/detector/unused_eager_loading.rb +35 -26
- data/lib/bullet/detector.rb +2 -0
- data/lib/bullet/ext/object.rb +9 -5
- data/lib/bullet/ext/string.rb +3 -1
- data/lib/bullet/mongoid4x.rb +9 -8
- data/lib/bullet/mongoid5x.rb +9 -8
- data/lib/bullet/mongoid6x.rb +13 -12
- data/lib/bullet/mongoid7x.rb +57 -0
- data/lib/bullet/notification/base.rb +28 -25
- data/lib/bullet/notification/counter_cache.rb +3 -1
- data/lib/bullet/notification/n_plus_one_query.rb +8 -7
- data/lib/bullet/notification/unused_eager_loading.rb +8 -7
- data/lib/bullet/notification.rb +4 -1
- data/lib/bullet/notification_collector.rb +2 -1
- data/lib/bullet/rack.rb +66 -35
- 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 +50 -20
- data/lib/bullet/version.rb +3 -2
- data/lib/bullet.rb +136 -55
- data/lib/generators/bullet/install_generator.rb +48 -0
- data/perf/benchmark.rb +19 -22
- data/rails/init.rb +2 -0
- data/spec/bullet/detector/association_spec.rb +6 -4
- data/spec/bullet/detector/base_spec.rb +2 -0
- data/spec/bullet/detector/counter_cache_spec.rb +17 -15
- data/spec/bullet/detector/n_plus_one_query_spec.rb +75 -46
- data/spec/bullet/detector/unused_eager_loading_spec.rb +45 -26
- data/spec/bullet/ext/object_spec.rb +18 -11
- data/spec/bullet/ext/string_spec.rb +7 -5
- data/spec/bullet/notification/base_spec.rb +38 -39
- data/spec/bullet/notification/counter_cache_spec.rb +5 -3
- data/spec/bullet/notification/n_plus_one_query_spec.rb +20 -5
- data/spec/bullet/notification/unused_eager_loading_spec.rb +9 -3
- data/spec/bullet/notification_collector_spec.rb +12 -10
- data/spec/bullet/rack_spec.rb +200 -48
- data/spec/bullet/registry/association_spec.rb +12 -10
- data/spec/bullet/registry/base_spec.rb +22 -20
- data/spec/bullet/registry/object_spec.rb +6 -4
- data/spec/bullet_spec.rb +64 -33
- data/spec/integration/{active_record4 → active_record}/association_spec.rb +238 -223
- data/spec/integration/counter_cache_spec.rb +26 -44
- data/spec/integration/mongoid/association_spec.rb +53 -65
- data/spec/models/address.rb +2 -0
- data/spec/models/attachment.rb +5 -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 +3 -1
- data/spec/models/company.rb +2 -0
- data/spec/models/country.rb +2 -0
- data/spec/models/deal.rb +5 -0
- data/spec/models/document.rb +4 -2
- 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 +3 -1
- data/spec/models/mongoid/category.rb +4 -2
- data/spec/models/mongoid/comment.rb +3 -1
- data/spec/models/mongoid/company.rb +3 -1
- data/spec/models/mongoid/entry.rb +3 -1
- data/spec/models/mongoid/post.rb +6 -4
- data/spec/models/mongoid/user.rb +2 -0
- data/spec/models/newspaper.rb +3 -1
- 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 +19 -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 +3 -0
- data/spec/models/teacher.rb +2 -0
- data/spec/models/user.rb +3 -0
- data/spec/models/writer.rb +2 -0
- data/spec/spec_helper.rb +19 -23
- data/spec/support/bullet_ext.rb +10 -9
- data/spec/support/mongo_seed.rb +38 -57
- data/spec/support/rack_double.rb +13 -19
- data/spec/support/sqlite_seed.rb +104 -76
- data/tasks/bullet_tasks.rake +4 -2
- data/test.sh +5 -0
- data/update.sh +3 -0
- metadata +34 -17
- data/.travis.yml +0 -16
- data/spec/integration/active_record5/association_spec.rb +0 -768
data/lib/bullet.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/module/delegation'
|
|
2
4
|
require 'set'
|
|
3
5
|
require 'uniform_notifier'
|
|
4
6
|
require 'bullet/ext/object'
|
|
@@ -12,45 +14,52 @@ module Bullet
|
|
|
12
14
|
autoload :ActiveRecord, "bullet/#{active_record_version}" if active_record?
|
|
13
15
|
autoload :Mongoid, "bullet/#{mongoid_version}" if mongoid?
|
|
14
16
|
autoload :Rack, 'bullet/rack'
|
|
17
|
+
autoload :ActiveJob, 'bullet/active_job'
|
|
15
18
|
autoload :Notification, 'bullet/notification'
|
|
16
19
|
autoload :Detector, 'bullet/detector'
|
|
17
20
|
autoload :Registry, 'bullet/registry'
|
|
18
21
|
autoload :NotificationCollector, 'bullet/notification_collector'
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
TRUE = 'true'.freeze
|
|
22
|
-
|
|
23
|
-
if defined? Rails::Railtie
|
|
23
|
+
if defined?(Rails::Railtie)
|
|
24
24
|
class BulletRailtie < Rails::Railtie
|
|
25
|
-
initializer
|
|
25
|
+
initializer 'bullet.configure_rails_initialization' do |app|
|
|
26
26
|
app.middleware.use Bullet::Rack
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
class << self
|
|
32
|
-
attr_writer :
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
attr_writer :n_plus_one_query_enable,
|
|
33
|
+
:unused_eager_loading_enable,
|
|
34
|
+
:counter_cache_enable,
|
|
35
|
+
:stacktrace_includes,
|
|
36
|
+
:stacktrace_excludes,
|
|
37
|
+
:skip_html_injection
|
|
38
|
+
attr_reader :safelist
|
|
39
|
+
attr_accessor :add_footer, :orm_patches_applied, :skip_http_headers
|
|
40
|
+
|
|
41
|
+
available_notifiers =
|
|
42
|
+
UniformNotifier::AVAILABLE_NOTIFIERS.select { |notifier| notifier != :raise }.map { |notifier| "#{notifier}=" }
|
|
43
|
+
available_notifiers_options = { to: UniformNotifier }
|
|
44
|
+
delegate(*available_notifiers, **available_notifiers_options)
|
|
39
45
|
|
|
40
46
|
def raise=(should_raise)
|
|
41
|
-
UniformNotifier.raise=(should_raise ? Notification::UnoptimizedQueryError : false)
|
|
47
|
+
UniformNotifier.raise = (should_raise ? Notification::UnoptimizedQueryError : false)
|
|
42
48
|
end
|
|
43
49
|
|
|
44
|
-
DETECTORS = [
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
DETECTORS = [
|
|
51
|
+
Bullet::Detector::NPlusOneQuery,
|
|
52
|
+
Bullet::Detector::UnusedEagerLoading,
|
|
53
|
+
Bullet::Detector::CounterCache
|
|
54
|
+
].freeze
|
|
47
55
|
|
|
48
56
|
def enable=(enable)
|
|
49
57
|
@enable = @n_plus_one_query_enable = @unused_eager_loading_enable = @counter_cache_enable = enable
|
|
58
|
+
|
|
50
59
|
if enable?
|
|
51
|
-
|
|
52
|
-
unless
|
|
53
|
-
self.
|
|
60
|
+
reset_safelist
|
|
61
|
+
unless orm_patches_applied
|
|
62
|
+
self.orm_patches_applied = true
|
|
54
63
|
Bullet::Mongoid.enable if mongoid?
|
|
55
64
|
Bullet::ActiveRecord.enable if active_record?
|
|
56
65
|
end
|
|
@@ -61,57 +70,113 @@ module Bullet
|
|
|
61
70
|
!!@enable
|
|
62
71
|
end
|
|
63
72
|
|
|
73
|
+
# Rails.root might be nil if `railties` is a dependency on a project that does not use Rails
|
|
74
|
+
def app_root
|
|
75
|
+
@app_root ||= (defined?(::Rails.root) && !::Rails.root.nil? ? Rails.root.to_s : Dir.pwd).to_s
|
|
76
|
+
end
|
|
77
|
+
|
|
64
78
|
def n_plus_one_query_enable?
|
|
65
|
-
|
|
79
|
+
enable? && !!@n_plus_one_query_enable
|
|
66
80
|
end
|
|
67
81
|
|
|
68
82
|
def unused_eager_loading_enable?
|
|
69
|
-
|
|
83
|
+
enable? && !!@unused_eager_loading_enable
|
|
70
84
|
end
|
|
71
85
|
|
|
72
86
|
def counter_cache_enable?
|
|
73
|
-
|
|
87
|
+
enable? && !!@counter_cache_enable
|
|
74
88
|
end
|
|
75
89
|
|
|
76
90
|
def stacktrace_includes
|
|
77
|
-
@stacktrace_includes
|
|
91
|
+
@stacktrace_includes ||= []
|
|
78
92
|
end
|
|
79
93
|
|
|
80
94
|
def stacktrace_excludes
|
|
81
|
-
@stacktrace_excludes
|
|
95
|
+
@stacktrace_excludes ||= []
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def add_safelist(options)
|
|
99
|
+
reset_safelist
|
|
100
|
+
@safelist[options[:type]][options[:class_name]] ||= []
|
|
101
|
+
@safelist[options[:type]][options[:class_name]] << options[:association].to_sym
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def delete_safelist(options)
|
|
105
|
+
reset_safelist
|
|
106
|
+
@safelist[options[:type]][options[:class_name]] ||= []
|
|
107
|
+
@safelist[options[:type]][options[:class_name]].delete(options[:association].to_sym)
|
|
108
|
+
@safelist[options[:type]].delete_if { |_key, val| val.empty? }
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def get_safelist_associations(type, class_name)
|
|
112
|
+
Array(@safelist[type][class_name])
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def reset_safelist
|
|
116
|
+
@safelist ||= { n_plus_one_query: {}, unused_eager_loading: {}, counter_cache: {} }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def clear_safelist
|
|
120
|
+
@safelist = nil
|
|
82
121
|
end
|
|
83
122
|
|
|
84
123
|
def add_whitelist(options)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
124
|
+
ActiveSupport::Deprecation.warn(<<~WARN.strip
|
|
125
|
+
add_whitelist is deprecated in favor of add_safelist. It will be removed from the next major release.
|
|
126
|
+
WARN
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
add_safelist(options)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def delete_whitelist(options)
|
|
133
|
+
ActiveSupport::Deprecation.warn(<<~WARN.strip
|
|
134
|
+
delete_whitelist is deprecated in favor of delete_safelist. It will be removed from the next major release.
|
|
135
|
+
WARN
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
delete_safelist(options)
|
|
88
139
|
end
|
|
89
140
|
|
|
90
141
|
def get_whitelist_associations(type, class_name)
|
|
91
|
-
|
|
142
|
+
ActiveSupport::Deprecation.warn(<<~WARN.strip
|
|
143
|
+
get_whitelist_associations is deprecated in favor of get_safelist_associations. It will be removed from the next major release.
|
|
144
|
+
WARN
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
get_safelist_associations(type, class_name)
|
|
92
148
|
end
|
|
93
149
|
|
|
94
150
|
def reset_whitelist
|
|
95
|
-
|
|
151
|
+
ActiveSupport::Deprecation.warn(<<~WARN.strip
|
|
152
|
+
reset_whitelist is deprecated in favor of reset_safelist. It will be removed from the next major release.
|
|
153
|
+
WARN
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
reset_safelist
|
|
96
157
|
end
|
|
97
158
|
|
|
98
159
|
def clear_whitelist
|
|
99
|
-
|
|
160
|
+
ActiveSupport::Deprecation.warn(<<~WARN.strip
|
|
161
|
+
clear_whitelist is deprecated in favor of clear_safelist. It will be removed from the next major release.
|
|
162
|
+
WARN
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
clear_safelist
|
|
100
166
|
end
|
|
101
167
|
|
|
102
168
|
def bullet_logger=(active)
|
|
103
169
|
if active
|
|
104
170
|
require 'fileutils'
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
bullet_log_file = File.open("#{root_path}/log/bullet.log", 'a+')
|
|
171
|
+
FileUtils.mkdir_p(app_root + '/log')
|
|
172
|
+
bullet_log_file = File.open("#{app_root}/log/bullet.log", 'a+')
|
|
108
173
|
bullet_log_file.sync = true
|
|
109
174
|
UniformNotifier.customized_logger = bullet_log_file
|
|
110
175
|
end
|
|
111
176
|
end
|
|
112
177
|
|
|
113
178
|
def debug(title, message)
|
|
114
|
-
puts "[Bullet][#{title}] #{message}" if ENV[BULLET_DEBUG] ==
|
|
179
|
+
puts "[Bullet][#{title}] #{message}" if ENV['BULLET_DEBUG'] == 'true'
|
|
115
180
|
end
|
|
116
181
|
|
|
117
182
|
def start_request
|
|
@@ -154,16 +219,15 @@ module Bullet
|
|
|
154
219
|
|
|
155
220
|
def notification?
|
|
156
221
|
return unless start?
|
|
222
|
+
|
|
157
223
|
Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
|
|
158
224
|
notification_collector.notifications_present?
|
|
159
225
|
end
|
|
160
226
|
|
|
161
227
|
def gather_inline_notifications
|
|
162
228
|
responses = []
|
|
163
|
-
for_each_active_notifier_with_notification
|
|
164
|
-
|
|
165
|
-
end
|
|
166
|
-
responses.join( "\n" )
|
|
229
|
+
for_each_active_notifier_with_notification { |notification| responses << notification.notify_inline }
|
|
230
|
+
responses.join("\n")
|
|
167
231
|
end
|
|
168
232
|
|
|
169
233
|
def perform_out_of_channel_notifications(env = {})
|
|
@@ -175,24 +239,30 @@ module Bullet
|
|
|
175
239
|
end
|
|
176
240
|
|
|
177
241
|
def footer_info
|
|
242
|
+
info = []
|
|
243
|
+
notification_collector.collection.each { |notification| info << notification.short_notice }
|
|
244
|
+
info
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def text_notifications
|
|
178
248
|
info = []
|
|
179
249
|
notification_collector.collection.each do |notification|
|
|
180
|
-
info << notification.
|
|
250
|
+
info << notification.notification_data.values.compact.join("\n")
|
|
181
251
|
end
|
|
182
252
|
info
|
|
183
253
|
end
|
|
184
254
|
|
|
185
255
|
def warnings
|
|
186
|
-
notification_collector.collection.
|
|
256
|
+
notification_collector.collection.each_with_object({}) do |notification, warnings|
|
|
187
257
|
warning_type = notification.class.to_s.split(':').last.tableize
|
|
188
258
|
warnings[warning_type] ||= []
|
|
189
259
|
warnings[warning_type] << notification
|
|
190
|
-
warnings
|
|
191
260
|
end
|
|
192
261
|
end
|
|
193
262
|
|
|
194
263
|
def profile
|
|
195
264
|
return_value = nil
|
|
265
|
+
|
|
196
266
|
if Bullet.enable?
|
|
197
267
|
begin
|
|
198
268
|
Bullet.start_request
|
|
@@ -210,24 +280,35 @@ module Bullet
|
|
|
210
280
|
return_value
|
|
211
281
|
end
|
|
212
282
|
|
|
283
|
+
def console_enabled?
|
|
284
|
+
UniformNotifier.active_notifiers.include?(UniformNotifier::JavascriptConsole)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def inject_into_page?
|
|
288
|
+
return false if defined?(@skip_html_injection) && @skip_html_injection
|
|
289
|
+
|
|
290
|
+
console_enabled? || add_footer
|
|
291
|
+
end
|
|
292
|
+
|
|
213
293
|
private
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
294
|
+
|
|
295
|
+
def for_each_active_notifier_with_notification
|
|
296
|
+
UniformNotifier.active_notifiers.each do |notifier|
|
|
297
|
+
notification_collector.collection.each do |notification|
|
|
298
|
+
notification.notifier = notifier
|
|
299
|
+
yield notification
|
|
220
300
|
end
|
|
221
301
|
end
|
|
302
|
+
end
|
|
222
303
|
|
|
223
|
-
|
|
224
|
-
|
|
304
|
+
def build_request_uri(env)
|
|
305
|
+
return "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']}" if env['REQUEST_URI']
|
|
225
306
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
end
|
|
307
|
+
if env['QUERY_STRING'].present?
|
|
308
|
+
"#{env['REQUEST_METHOD']} #{env['PATH_INFO']}?#{env['QUERY_STRING']}"
|
|
309
|
+
else
|
|
310
|
+
"#{env['REQUEST_METHOD']} #{env['PATH_INFO']}"
|
|
231
311
|
end
|
|
312
|
+
end
|
|
232
313
|
end
|
|
233
314
|
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bullet
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < ::Rails::Generators::Base
|
|
6
|
+
desc <<~DESC
|
|
7
|
+
Description:
|
|
8
|
+
Enable bullet in development/test for your application.
|
|
9
|
+
DESC
|
|
10
|
+
|
|
11
|
+
def enable_in_development
|
|
12
|
+
environment(nil, env: 'development') do
|
|
13
|
+
<<~FILE
|
|
14
|
+
config.after_initialize do
|
|
15
|
+
Bullet.enable = true
|
|
16
|
+
Bullet.alert = true
|
|
17
|
+
Bullet.bullet_logger = true
|
|
18
|
+
Bullet.console = true
|
|
19
|
+
# Bullet.growl = true
|
|
20
|
+
Bullet.rails_logger = true
|
|
21
|
+
Bullet.add_footer = true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
FILE
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
say 'Enabled bullet in config/environments/development.rb'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def enable_in_test
|
|
31
|
+
return unless yes?('Would you like to enable bullet in test environment? (y/n)')
|
|
32
|
+
|
|
33
|
+
environment(nil, env: 'test') do
|
|
34
|
+
<<~FILE
|
|
35
|
+
config.after_initialize do
|
|
36
|
+
Bullet.enable = true
|
|
37
|
+
Bullet.bullet_logger = true
|
|
38
|
+
Bullet.raise = true # raise an error if n+1 query occurs
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
FILE
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
say 'Enabled bullet in config/environments/test.rb'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
data/perf/benchmark.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH << 'lib'
|
|
2
4
|
require 'benchmark'
|
|
3
5
|
require 'rails'
|
|
4
6
|
require 'active_record'
|
|
@@ -27,13 +29,16 @@ class User < ActiveRecord::Base
|
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
# create database bullet_benchmark;
|
|
30
|
-
ActiveRecord::Base.establish_connection(
|
|
32
|
+
ActiveRecord::Base.establish_connection(
|
|
33
|
+
adapter: 'mysql2',
|
|
34
|
+
database: 'bullet_benchmark',
|
|
35
|
+
server: '/tmp/mysql.socket',
|
|
36
|
+
username: 'root'
|
|
37
|
+
)
|
|
31
38
|
|
|
32
|
-
ActiveRecord::Base.connection.tables.each
|
|
33
|
-
ActiveRecord::Base.connection.drop_table(table)
|
|
34
|
-
end
|
|
39
|
+
ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
|
|
35
40
|
|
|
36
|
-
ActiveRecord::Schema.define(:
|
|
41
|
+
ActiveRecord::Schema.define(version: 1) do
|
|
37
42
|
create_table :posts do |t|
|
|
38
43
|
t.column :title, :string
|
|
39
44
|
t.column :body, :string
|
|
@@ -52,30 +57,23 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
|
52
57
|
end
|
|
53
58
|
|
|
54
59
|
users_size = 100
|
|
55
|
-
posts_size =
|
|
56
|
-
comments_size =
|
|
60
|
+
posts_size = 1_000
|
|
61
|
+
comments_size = 10_000
|
|
57
62
|
users = []
|
|
58
|
-
users_size.times
|
|
59
|
-
users << User.new(:name => "user#{i}")
|
|
60
|
-
end
|
|
63
|
+
users_size.times { |i| users << User.new(name: "user#{i}") }
|
|
61
64
|
User.import users
|
|
62
65
|
users = User.all
|
|
63
66
|
|
|
64
67
|
posts = []
|
|
65
|
-
posts_size.times
|
|
66
|
-
posts << Post.new(:title => "Title #{i}", :body => "Body #{i}", :user => users[i%100])
|
|
67
|
-
end
|
|
68
|
+
posts_size.times { |i| posts << Post.new(title: "Title #{i}", body: "Body #{i}", user: users[i % 100]) }
|
|
68
69
|
Post.import posts
|
|
69
70
|
posts = Post.all
|
|
70
71
|
|
|
71
72
|
comments = []
|
|
72
|
-
comments_size.times
|
|
73
|
-
comments << Comment.new(:body => "Comment #{i}", :post => posts[i%1000], :user => users[i%100])
|
|
74
|
-
end
|
|
73
|
+
comments_size.times { |i| comments << Comment.new(body: "Comment #{i}", post: posts[i % 1_000], user: users[i % 100]) }
|
|
75
74
|
Comment.import comments
|
|
76
75
|
|
|
77
|
-
puts
|
|
78
|
-
|
|
76
|
+
puts 'Start benchmarking...'
|
|
79
77
|
|
|
80
78
|
Bullet.enable = true
|
|
81
79
|
|
|
@@ -83,7 +81,7 @@ Benchmark.bm(70) do |bm|
|
|
|
83
81
|
bm.report("Querying & Iterating #{posts_size} Posts with #{comments_size} Comments and #{users_size} Users") do
|
|
84
82
|
10.times do
|
|
85
83
|
Bullet.start_request
|
|
86
|
-
Post.select(
|
|
84
|
+
Post.select('SQL_NO_CACHE *').includes(:user, comments: :user).each do |p|
|
|
87
85
|
p.title
|
|
88
86
|
p.user.name
|
|
89
87
|
p.comments.each do |c|
|
|
@@ -96,8 +94,7 @@ Benchmark.bm(70) do |bm|
|
|
|
96
94
|
end
|
|
97
95
|
end
|
|
98
96
|
|
|
99
|
-
puts
|
|
100
|
-
|
|
97
|
+
puts 'End benchmarking...'
|
|
101
98
|
|
|
102
99
|
# Run benchmark with bundler
|
|
103
100
|
#
|
data/rails/init.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
module Bullet
|
|
@@ -8,15 +10,15 @@ module Bullet
|
|
|
8
10
|
@post2 = Post.last
|
|
9
11
|
end
|
|
10
12
|
|
|
11
|
-
context
|
|
12
|
-
it
|
|
13
|
+
context '.add_object_association' do
|
|
14
|
+
it 'should add object, associations pair' do
|
|
13
15
|
Association.add_object_associations(@post1, :associations)
|
|
14
16
|
expect(Association.send(:object_associations)).to be_include(@post1.bullet_key, :associations)
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
context
|
|
19
|
-
it
|
|
20
|
+
context '.add_call_object_associations' do
|
|
21
|
+
it 'should add call object, associations pair' do
|
|
20
22
|
Association.add_call_object_associations(@post1, :associations)
|
|
21
23
|
expect(Association.send(:call_object_associations)).to be_include(@post1.bullet_key, :associations)
|
|
22
24
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'spec_helper'
|
|
2
4
|
|
|
3
5
|
module Bullet
|
|
@@ -8,44 +10,44 @@ module Bullet
|
|
|
8
10
|
@post2 = Post.last
|
|
9
11
|
end
|
|
10
12
|
|
|
11
|
-
context
|
|
12
|
-
it
|
|
13
|
-
expect(CounterCache).to receive(:conditions_met?).with(@post1, [
|
|
14
|
-
expect(CounterCache).to receive(:create_notification).with(
|
|
15
|
-
CounterCache.add_counter_cache(@post1, [
|
|
13
|
+
context '.add_counter_cache' do
|
|
14
|
+
it 'should create notification if conditions met' do
|
|
15
|
+
expect(CounterCache).to receive(:conditions_met?).with(@post1, %i[comments]).and_return(true)
|
|
16
|
+
expect(CounterCache).to receive(:create_notification).with('Post', %i[comments])
|
|
17
|
+
CounterCache.add_counter_cache(@post1, %i[comments])
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
it
|
|
19
|
-
expect(CounterCache).to receive(:conditions_met?).with(@post1, [
|
|
20
|
+
it 'should not create notification if conditions not met' do
|
|
21
|
+
expect(CounterCache).to receive(:conditions_met?).with(@post1, %i[comments]).and_return(false)
|
|
20
22
|
expect(CounterCache).to receive(:create_notification).never
|
|
21
|
-
CounterCache.add_counter_cache(@post1, [
|
|
23
|
+
CounterCache.add_counter_cache(@post1, %i[comments])
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
context
|
|
26
|
-
it
|
|
27
|
+
context '.add_possible_objects' do
|
|
28
|
+
it 'should add possible objects' do
|
|
27
29
|
CounterCache.add_possible_objects([@post1, @post2])
|
|
28
30
|
expect(CounterCache.possible_objects).to be_include(@post1.bullet_key)
|
|
29
31
|
expect(CounterCache.possible_objects).to be_include(@post2.bullet_key)
|
|
30
32
|
end
|
|
31
33
|
|
|
32
|
-
it
|
|
34
|
+
it 'should add impossible object' do
|
|
33
35
|
CounterCache.add_impossible_object(@post1)
|
|
34
36
|
expect(CounterCache.impossible_objects).to be_include(@post1.bullet_key)
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
39
|
|
|
38
|
-
context
|
|
39
|
-
it
|
|
40
|
+
context '.conditions_met?' do
|
|
41
|
+
it 'should be true when object is possible, not impossible' do
|
|
40
42
|
CounterCache.add_possible_objects(@post1)
|
|
41
43
|
expect(CounterCache.conditions_met?(@post1, :associations)).to eq true
|
|
42
44
|
end
|
|
43
45
|
|
|
44
|
-
it
|
|
46
|
+
it 'should be false when object is not possible' do
|
|
45
47
|
expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
|
|
46
48
|
end
|
|
47
49
|
|
|
48
|
-
it
|
|
50
|
+
it 'should be false when object is possible, and impossible' do
|
|
49
51
|
CounterCache.add_possible_objects(@post1)
|
|
50
52
|
CounterCache.add_impossible_object(@post1)
|
|
51
53
|
expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
|