bullet 5.9.0 → 6.1.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.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +22 -1
  3. data/CHANGELOG.md +27 -0
  4. data/Gemfile.rails-4.0 +1 -1
  5. data/Gemfile.rails-4.1 +1 -1
  6. data/Gemfile.rails-4.2 +1 -1
  7. data/Gemfile.rails-5.0 +1 -1
  8. data/Gemfile.rails-5.1 +1 -1
  9. data/Gemfile.rails-5.2 +1 -1
  10. data/Gemfile.rails-6.0 +15 -0
  11. data/Gemfile.rails-6.1 +15 -0
  12. data/README.md +31 -10
  13. data/lib/bullet.rb +50 -26
  14. data/lib/bullet/active_job.rb +13 -0
  15. data/lib/bullet/active_record4.rb +9 -32
  16. data/lib/bullet/active_record41.rb +7 -27
  17. data/lib/bullet/active_record42.rb +8 -24
  18. data/lib/bullet/active_record5.rb +188 -179
  19. data/lib/bullet/active_record52.rb +176 -168
  20. data/lib/bullet/active_record60.rb +267 -0
  21. data/lib/bullet/active_record61.rb +267 -0
  22. data/lib/bullet/bullet_xhr.js +63 -0
  23. data/lib/bullet/dependency.rb +50 -36
  24. data/lib/bullet/detector/association.rb +26 -20
  25. data/lib/bullet/detector/base.rb +1 -2
  26. data/lib/bullet/detector/counter_cache.rb +13 -9
  27. data/lib/bullet/detector/n_plus_one_query.rb +22 -12
  28. data/lib/bullet/detector/unused_eager_loading.rb +6 -3
  29. data/lib/bullet/ext/object.rb +4 -2
  30. data/lib/bullet/mongoid4x.rb +2 -6
  31. data/lib/bullet/mongoid5x.rb +2 -6
  32. data/lib/bullet/mongoid6x.rb +2 -6
  33. data/lib/bullet/mongoid7x.rb +2 -6
  34. data/lib/bullet/notification/base.rb +14 -18
  35. data/lib/bullet/notification/n_plus_one_query.rb +2 -4
  36. data/lib/bullet/notification/unused_eager_loading.rb +2 -4
  37. data/lib/bullet/rack.rb +50 -25
  38. data/lib/bullet/stack_trace_filter.rb +6 -12
  39. data/lib/bullet/version.rb +1 -1
  40. data/lib/generators/bullet/install_generator.rb +23 -23
  41. data/perf/benchmark.rb +8 -14
  42. data/spec/bullet/detector/counter_cache_spec.rb +6 -6
  43. data/spec/bullet/detector/n_plus_one_query_spec.rb +7 -3
  44. data/spec/bullet/detector/unused_eager_loading_spec.rb +19 -6
  45. data/spec/bullet/ext/object_spec.rb +9 -4
  46. data/spec/bullet/notification/base_spec.rb +1 -3
  47. data/spec/bullet/notification/n_plus_one_query_spec.rb +16 -3
  48. data/spec/bullet/notification/unused_eager_loading_spec.rb +5 -1
  49. data/spec/bullet/rack_spec.rb +86 -6
  50. data/spec/bullet/registry/association_spec.rb +2 -2
  51. data/spec/bullet/registry/base_spec.rb +1 -1
  52. data/spec/bullet_spec.rb +11 -30
  53. data/spec/integration/active_record/association_spec.rb +44 -136
  54. data/spec/integration/counter_cache_spec.rb +11 -31
  55. data/spec/integration/mongoid/association_spec.rb +18 -32
  56. data/spec/models/folder.rb +1 -2
  57. data/spec/models/group.rb +1 -2
  58. data/spec/models/page.rb +1 -2
  59. data/spec/models/writer.rb +1 -2
  60. data/spec/spec_helper.rb +6 -10
  61. data/spec/support/bullet_ext.rb +8 -9
  62. data/spec/support/mongo_seed.rb +2 -16
  63. data/test.sh +1 -0
  64. metadata +12 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: fefb038c3c46f100cc22cdd95c417c781aff2943
4
- data.tar.gz: ad23b5755c4956788bad2b3ae98323d6e24c2bb8
2
+ SHA256:
3
+ metadata.gz: 6d02240600f13580ed16200edd5c39563bec1cb49a46ccbc82c57cff73a46e2f
4
+ data.tar.gz: 0f40a4a1fe6157dabec88cb0ecc817168eda794aa1177c41ede1df351695d76a
5
5
  SHA512:
6
- metadata.gz: 79f4e0bb1d4e62df6460fd668f0789936e3e0b1c36d078bb13ec2788f9d69f46e0dd3615e1983019bc4c83d6e7d2b2195377c5216a23038d270aee2ddfb6e77c
7
- data.tar.gz: 504905ca503f0727e71c1c476ab058eab57618bc6a4a9084411c479ebd63913c75ac178cf27566d05e800887e1d6f1e709aa89733632743c7216db810d410fb8
6
+ metadata.gz: 1d3d3ce81767ce81091ddd7412dd8f341190ffac085477cde3ea04fa1ed696661f84be64d9c1fb6e6a0de276788e56f18aaada213df712cb51e6efb0a577ec37
7
+ data.tar.gz: a3633af514a31e0ad6ff317a98616ed2c6c3ce070109288b8514c80277d4098359ed25a60bd5bcc4cd0ebf469f156751fa707f8d410f010bfcb8828e206e08a3
@@ -1,12 +1,33 @@
1
- sudo: false
2
1
  language: ruby
3
2
  rvm:
4
3
  - 2.3.0
4
+ - 2.6.0
5
5
  gemfile:
6
+ - Gemfile.rails-6.0
7
+ - Gemfile.rails-5.2
6
8
  - Gemfile.rails-5.1
7
9
  - Gemfile.rails-5.0
8
10
  - Gemfile.rails-4.2
9
11
  - Gemfile.rails-4.1
10
12
  - Gemfile.rails-4.0
13
+ matrix:
14
+ exclude:
15
+ - rvm: 2.3.0
16
+ gemfile: Gemfile.rails-6.0
17
+ - rvm: 2.6.0
18
+ gemfile: Gemfile.rails-5.2
19
+ - rvm: 2.6.0
20
+ gemfile: Gemfile.rails-5.1
21
+ - rvm: 2.6.0
22
+ gemfile: Gemfile.rails-5.0
23
+ - rvm: 2.6.0
24
+ gemfile: Gemfile.rails-4.2
25
+ - rvm: 2.6.0
26
+ gemfile: Gemfile.rails-4.1
27
+ - rvm: 2.6.0
28
+ gemfile: Gemfile.rails-4.0
11
29
  env:
12
30
  - DB=sqlite
31
+ before_install:
32
+ - "find /home/travis/.rvm/rubies -wholename '*default/bundler-*.gemspec' -delete"
33
+ - gem install bundler -v '< 2'
@@ -1,5 +1,32 @@
1
1
  ## Next Release
2
2
 
3
+ ## 6.1.1 (12/12/2020)
4
+
5
+ * Add support Rails 6.1
6
+ * Make whitelist thread safe
7
+
8
+ ## 6.1.0 (12/28/2019)
9
+
10
+ * Add skip_html_injection flag
11
+ * Remove writer hack in active_record6
12
+ * Use modern includes syntax in warnings
13
+ * Fix warning: The last argument is used as the keyword parameter
14
+
15
+ ## 6.0.2 (08/20/2019)
16
+
17
+ * Fully support Rails 6.0
18
+
19
+ ## 6.0.1 (06/26/2019)
20
+
21
+ * Add Bullet::ActiveJob
22
+ * Prevent "Maximum call stack exceeded" errors when used with Turbolinks
23
+
24
+ ## 6.0.0 (04/25/2019)
25
+
26
+ * Add XHR support to Bullet
27
+ * Support Rails 6.0
28
+ * Handle case where ID is manually set on unpersisted record
29
+
3
30
  ## 5.9.0 (11/11/2018)
4
31
 
5
32
  * Require Ruby 2.3+
@@ -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]
@@ -3,7 +3,7 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem 'rails', '~> 4.1.0'
6
- gem 'sqlite3'
6
+ gem 'sqlite3', '~> 1.3.6'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
9
  gem 'tins', '~> 1.6.0', platforms: [:ruby_19]
@@ -3,7 +3,7 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem 'rails', '~> 4.2.0'
6
- gem 'sqlite3'
6
+ gem 'sqlite3', '~> 1.3.6'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
9
  gem 'tins', '~> 1.6.0', platforms: [:ruby_19]
@@ -3,7 +3,7 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem 'rails', '~> 5.0.0'
6
- gem 'sqlite3'
6
+ gem 'sqlite3', '~> 1.3.6'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
9
 
@@ -3,7 +3,7 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem 'rails', '~> 5.1.0'
6
- gem 'sqlite3'
6
+ gem 'sqlite3', '~> 1.3.6'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
9
 
@@ -3,7 +3,7 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem 'rails', '~> 5.2.0'
6
- gem 'sqlite3'
6
+ gem 'sqlite3', '~> 1.3.6'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
9
 
@@ -0,0 +1,15 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 6.0.0'
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
@@ -0,0 +1,15 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '~> 6.1.0'
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
@@ -1,7 +1,7 @@
1
1
  # Bullet
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/bullet.png)](http://badge.fury.io/rb/bullet)
4
- [![Build Status](https://secure.travis-ci.org/flyerhzm/bullet.png)](http://travis-ci.org/flyerhzm/bullet)
3
+ [![Gem Version](https://badge.fury.io/rb/bullet.svg)](http://badge.fury.io/rb/bullet)
4
+ [![Build Status](https://secure.travis-ci.org/flyerhzm/bullet.svg)](http://travis-ci.org/flyerhzm/bullet)
5
5
  [![AwesomeCode Status for flyerhzm/bullet](https://awesomecode.io/projects/6755235b-e2c1-459e-bf92-b8b13d0c0472/status)](https://awesomecode.io/repos/flyerhzm/bullet)
6
6
  [![Coderwall Endorse](http://api.coderwall.com/flyerhzm/endorsecount.png)](http://coderwall.com/flyerhzm)
7
7
 
@@ -37,6 +37,13 @@ or add it into a Gemfile (Bundler):
37
37
  gem 'bullet', group: 'development'
38
38
  ```
39
39
 
40
+ enable the Bullet gem with generate command
41
+
42
+ ```ruby
43
+ bundle exec rails g bullet:install
44
+ ```
45
+ The generate command will auto generate the default configuration and may ask to include in the test environment as well. See below for custom configuration.
46
+
40
47
  **Note**: make sure `bullet` gem is added after activerecord (rails) and
41
48
  mongoid.
42
49
 
@@ -63,6 +70,7 @@ config.after_initialize do
63
70
  Bullet.airbrake = true
64
71
  Bullet.rollbar = true
65
72
  Bullet.add_footer = true
73
+ Bullet.skip_html_injection = false
66
74
  Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
67
75
  Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware', ['my_file.rb', 'my_method'], ['my_file.rb', 16..20] ]
68
76
  Bullet.slack = { webhook_url: 'http://some.slack.url', channel: '#default', username: 'notifier' }
@@ -85,6 +93,7 @@ The code above will enable all of the Bullet notification systems:
85
93
  * `Bullet.rollbar`: add notifications to rollbar
86
94
  * `Bullet.sentry`: add notifications to sentry
87
95
  * `Bullet.add_footer`: adds the details in the bottom left corner of the page. Double click the footer or use close button to hide footer.
96
+ * `Bullet.skip_html_injection`: prevents Bullet from injecting XHR into the returned HTML. This must be false for receiving alerts or console logging.
88
97
  * `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
89
98
  * `Bullet.stacktrace_excludes`: ignore paths with any of these substrings in the stack trace, even if they are not in your main app.
90
99
  Each item can be a string (match substring), a regex, or an array where the first item is a path to match, and the second
@@ -125,7 +134,7 @@ do like
125
134
 
126
135
  ```ruby
127
136
  class ApplicationController < ActionController::Base
128
- around_action :skip_bullet
137
+ around_action :skip_bullet, if: -> { defined?(Bullet) }
129
138
 
130
139
  def skip_bullet
131
140
  previous_value = Bullet.enable?
@@ -181,15 +190,27 @@ If you find Bullet does not work for you, *please disable your browser's cache*.
181
190
 
182
191
  ## Advanced
183
192
 
184
- ### Profile a job
193
+ ### Work with ActiveJob
185
194
 
186
- The Bullet gem uses rack middleware to profile requests. If you want to use Bullet without an http server, like to profile a job, you can use the profile method and fetch warnings
195
+ Include `Bullet::ActiveJob` in your `ApplicationJob`.
187
196
 
188
197
  ```ruby
189
- Bullet.profile do
190
- # do anything
198
+ class ApplicationJob < ActiveJob::Base
199
+ include Bullet::ActiveJob if Rails.env.development?
200
+ end
201
+ ```
202
+
203
+ ### Work with other background job solution
204
+
205
+ Use the Bullet.profile method.
191
206
 
192
- warnings = Bullet.warnings
207
+ ```ruby
208
+ class ApplicationJob < ActiveJob::Base
209
+ around_perform do |_job, block|
210
+ Bullet.profile do
211
+ block.call
212
+ end
213
+ end
193
214
  end
194
215
  ```
195
216
 
@@ -221,7 +242,7 @@ end
221
242
  Then wrap each test in Bullet api.
222
243
 
223
244
  ```ruby
224
- # spec/spec_helper.rb
245
+ # spec/rails_helper.rb
225
246
  if Bullet.enable?
226
247
  config.before(:each) do
227
248
  Bullet.start_request
@@ -458,4 +479,4 @@ Meanwhile, there's a line appended to `log/bullet.log`
458
479
  Post => [:comments]
459
480
  ```
460
481
 
461
- Copyright (c) 2009 - 2016 Richard Huang (flyerhzm@gmail.com), released under the MIT license
482
+ Copyright (c) 2009 - 2019 Richard Huang (flyerhzm@gmail.com), released under the MIT license
@@ -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'
@@ -22,7 +23,7 @@ module Bullet
22
23
  BULLET_DEBUG = 'BULLET_DEBUG'
23
24
  TRUE = 'true'
24
25
 
25
- if defined? Rails::Railtie
26
+ if defined?(Rails::Railtie)
26
27
  class BulletRailtie < Rails::Railtie
27
28
  initializer 'bullet.configure_rails_initialization' do |app|
28
29
  app.middleware.use Bullet::Rack
@@ -31,28 +32,35 @@ module Bullet
31
32
  end
32
33
 
33
34
  class << self
34
- attr_writer :n_plus_one_query_enable, :unused_eager_loading_enable, :counter_cache_enable, :stacktrace_includes, :stacktrace_excludes
35
- attr_reader :whitelist
36
- attr_accessor :add_footer, :orm_pathches_applied
35
+ attr_writer :n_plus_one_query_enable,
36
+ :unused_eager_loading_enable,
37
+ :counter_cache_enable,
38
+ :stacktrace_includes,
39
+ :stacktrace_excludes,
40
+ :skip_html_injection
41
+ attr_accessor :add_footer, :orm_patches_applied
37
42
 
38
43
  available_notifiers = UniformNotifier::AVAILABLE_NOTIFIERS.map { |notifier| "#{notifier}=" }
39
- available_notifiers << { to: UniformNotifier }
40
- delegate(*available_notifiers)
44
+ available_notifiers_options = { to: UniformNotifier }
45
+ delegate(*available_notifiers, **available_notifiers_options)
41
46
 
42
47
  def raise=(should_raise)
43
48
  UniformNotifier.raise = (should_raise ? Notification::UnoptimizedQueryError : false)
44
49
  end
45
50
 
46
- DETECTORS = [Bullet::Detector::NPlusOneQuery,
47
- Bullet::Detector::UnusedEagerLoading,
48
- Bullet::Detector::CounterCache].freeze
51
+ DETECTORS = [
52
+ Bullet::Detector::NPlusOneQuery,
53
+ Bullet::Detector::UnusedEagerLoading,
54
+ Bullet::Detector::CounterCache
55
+ ].freeze
49
56
 
50
57
  def enable=(enable)
51
58
  @enable = @n_plus_one_query_enable = @unused_eager_loading_enable = @counter_cache_enable = enable
59
+
52
60
  if enable?
53
61
  reset_whitelist
54
- unless orm_pathches_applied
55
- self.orm_pathches_applied = true
62
+ unless orm_patches_applied
63
+ self.orm_patches_applied = true
56
64
  Bullet::Mongoid.enable if mongoid?
57
65
  Bullet::ActiveRecord.enable if active_record?
58
66
  end
@@ -63,6 +71,10 @@ module Bullet
63
71
  !!@enable
64
72
  end
65
73
 
74
+ def app_root
75
+ (defined?(::Rails.root) ? Rails.root.to_s : Dir.pwd).to_s
76
+ end
77
+
66
78
  def n_plus_one_query_enable?
67
79
  enable? && !!@n_plus_one_query_enable
68
80
  end
@@ -85,35 +97,34 @@ module Bullet
85
97
 
86
98
  def add_whitelist(options)
87
99
  reset_whitelist
88
- @whitelist[options[:type]][options[:class_name]] ||= []
89
- @whitelist[options[:type]][options[:class_name]] << options[:association].to_sym
100
+ Thread.current[:whitelist][options[:type]][options[:class_name]] ||= []
101
+ Thread.current[:whitelist][options[:type]][options[:class_name]] << options[:association].to_sym
90
102
  end
91
103
 
92
104
  def delete_whitelist(options)
93
105
  reset_whitelist
94
- @whitelist[options[:type]][options[:class_name]] ||= []
95
- @whitelist[options[:type]][options[:class_name]].delete(options[:association].to_sym)
96
- @whitelist[options[:type]].delete_if { |_key, val| val.empty? }
106
+ Thread.current[:whitelist][options[:type]][options[:class_name]] ||= []
107
+ Thread.current[:whitelist][options[:type]][options[:class_name]].delete(options[:association].to_sym)
108
+ Thread.current[:whitelist][options[:type]].delete_if { |_key, val| val.empty? }
97
109
  end
98
110
 
99
111
  def get_whitelist_associations(type, class_name)
100
- Array(@whitelist[type][class_name])
112
+ Array(Thread.current[:whitelist][type][class_name])
101
113
  end
102
114
 
103
115
  def reset_whitelist
104
- @whitelist ||= { n_plus_one_query: {}, unused_eager_loading: {}, counter_cache: {} }
116
+ Thread.current[:whitelist] ||= { n_plus_one_query: {}, unused_eager_loading: {}, counter_cache: {} }
105
117
  end
106
118
 
107
119
  def clear_whitelist
108
- @whitelist = nil
120
+ Thread.current[:whitelist] = nil
109
121
  end
110
122
 
111
123
  def bullet_logger=(active)
112
124
  if active
113
125
  require 'fileutils'
114
- root_path = (rails? ? Rails.root.to_s : Dir.pwd).to_s
115
- FileUtils.mkdir_p(root_path + '/log')
116
- bullet_log_file = File.open("#{root_path}/log/bullet.log", 'a+')
126
+ FileUtils.mkdir_p(app_root + '/log')
127
+ bullet_log_file = File.open("#{app_root}/log/bullet.log", 'a+')
117
128
  bullet_log_file.sync = true
118
129
  UniformNotifier.customized_logger = bullet_log_file
119
130
  end
@@ -170,9 +181,7 @@ module Bullet
170
181
 
171
182
  def gather_inline_notifications
172
183
  responses = []
173
- for_each_active_notifier_with_notification do |notification|
174
- responses << notification.notify_inline
175
- end
184
+ for_each_active_notifier_with_notification { |notification| responses << notification.notify_inline }
176
185
  responses.join("\n")
177
186
  end
178
187
 
@@ -185,9 +194,15 @@ module Bullet
185
194
  end
186
195
 
187
196
  def footer_info
197
+ info = []
198
+ notification_collector.collection.each { |notification| info << notification.short_notice }
199
+ info
200
+ end
201
+
202
+ def text_notifications
188
203
  info = []
189
204
  notification_collector.collection.each do |notification|
190
- info << notification.short_notice
205
+ info << notification.notification_data.values.compact.join("\n")
191
206
  end
192
207
  info
193
208
  end
@@ -202,6 +217,7 @@ module Bullet
202
217
 
203
218
  def profile
204
219
  return_value = nil
220
+
205
221
  if Bullet.enable?
206
222
  begin
207
223
  Bullet.start_request
@@ -219,6 +235,14 @@ module Bullet
219
235
  return_value
220
236
  end
221
237
 
238
+ def console_enabled?
239
+ UniformNotifier.active_notifiers.include?(UniformNotifier::JavascriptConsole)
240
+ end
241
+
242
+ def inject_into_page?
243
+ !@skip_html_injection && (console_enabled? || add_footer)
244
+ end
245
+
222
246
  private
223
247
 
224
248
  def for_each_active_notifier_with_notification
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bullet
4
+ module ActiveJob
5
+ def self.included(base)
6
+ base.class_eval do
7
+ around_perform do |_job, block|
8
+ Bullet.profile { block.call }
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end