bullet 5.9.0 → 7.0.4

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 (71) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/main.yml +82 -0
  3. data/CHANGELOG.md +72 -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/Gemfile.rails-7.0 +10 -0
  13. data/MIT-LICENSE +1 -1
  14. data/README.md +59 -33
  15. data/lib/bullet/active_job.rb +13 -0
  16. data/lib/bullet/active_record4.rb +9 -32
  17. data/lib/bullet/active_record41.rb +8 -27
  18. data/lib/bullet/active_record42.rb +9 -24
  19. data/lib/bullet/active_record5.rb +190 -179
  20. data/lib/bullet/active_record52.rb +184 -169
  21. data/lib/bullet/active_record60.rb +274 -0
  22. data/lib/bullet/active_record61.rb +274 -0
  23. data/lib/bullet/active_record70.rb +277 -0
  24. data/lib/bullet/bullet_xhr.js +64 -0
  25. data/lib/bullet/dependency.rb +60 -36
  26. data/lib/bullet/detector/association.rb +26 -20
  27. data/lib/bullet/detector/counter_cache.rb +15 -11
  28. data/lib/bullet/detector/n_plus_one_query.rb +24 -14
  29. data/lib/bullet/detector/unused_eager_loading.rb +8 -5
  30. data/lib/bullet/ext/object.rb +4 -2
  31. data/lib/bullet/mongoid4x.rb +3 -7
  32. data/lib/bullet/mongoid5x.rb +3 -7
  33. data/lib/bullet/mongoid6x.rb +3 -7
  34. data/lib/bullet/mongoid7x.rb +34 -23
  35. data/lib/bullet/notification/base.rb +14 -18
  36. data/lib/bullet/notification/n_plus_one_query.rb +2 -4
  37. data/lib/bullet/notification/unused_eager_loading.rb +2 -4
  38. data/lib/bullet/notification.rb +2 -1
  39. data/lib/bullet/rack.rb +55 -27
  40. data/lib/bullet/stack_trace_filter.rb +11 -19
  41. data/lib/bullet/version.rb +1 -1
  42. data/lib/bullet.rb +68 -42
  43. data/lib/generators/bullet/install_generator.rb +22 -23
  44. data/perf/benchmark.rb +11 -14
  45. data/spec/bullet/detector/counter_cache_spec.rb +6 -6
  46. data/spec/bullet/detector/n_plus_one_query_spec.rb +8 -4
  47. data/spec/bullet/detector/unused_eager_loading_spec.rb +25 -8
  48. data/spec/bullet/ext/object_spec.rb +10 -5
  49. data/spec/bullet/notification/base_spec.rb +5 -7
  50. data/spec/bullet/notification/n_plus_one_query_spec.rb +16 -3
  51. data/spec/bullet/notification/unused_eager_loading_spec.rb +5 -1
  52. data/spec/bullet/rack_spec.rb +161 -11
  53. data/spec/bullet/registry/association_spec.rb +2 -2
  54. data/spec/bullet/registry/base_spec.rb +1 -1
  55. data/spec/bullet_spec.rb +25 -44
  56. data/spec/integration/active_record/association_spec.rb +115 -144
  57. data/spec/integration/counter_cache_spec.rb +14 -34
  58. data/spec/integration/mongoid/association_spec.rb +19 -33
  59. data/spec/models/attachment.rb +5 -0
  60. data/spec/models/deal.rb +5 -0
  61. data/spec/models/post.rb +2 -0
  62. data/spec/models/role.rb +7 -0
  63. data/spec/models/submission.rb +1 -0
  64. data/spec/models/user.rb +2 -0
  65. data/spec/spec_helper.rb +4 -10
  66. data/spec/support/bullet_ext.rb +8 -9
  67. data/spec/support/mongo_seed.rb +3 -16
  68. data/spec/support/sqlite_seed.rb +38 -0
  69. data/test.sh +3 -0
  70. metadata +21 -8
  71. data/.travis.yml +0 -12
data/lib/bullet.rb CHANGED
@@ -14,15 +14,13 @@ 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'
20
21
  autoload :NotificationCollector, 'bullet/notification_collector'
21
22
 
22
- BULLET_DEBUG = 'BULLET_DEBUG'
23
- TRUE = 'true'
24
-
25
- if defined? Rails::Railtie
23
+ if defined?(Rails::Railtie)
26
24
  class BulletRailtie < Rails::Railtie
27
25
  initializer 'bullet.configure_rails_initialization' do |app|
28
26
  app.middleware.use Bullet::Rack
@@ -31,28 +29,37 @@ module Bullet
31
29
  end
32
30
 
33
31
  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
37
-
38
- available_notifiers = UniformNotifier::AVAILABLE_NOTIFIERS.map { |notifier| "#{notifier}=" }
39
- available_notifiers << { to: UniformNotifier }
40
- delegate(*available_notifiers)
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)
41
45
 
42
46
  def raise=(should_raise)
43
47
  UniformNotifier.raise = (should_raise ? Notification::UnoptimizedQueryError : false)
44
48
  end
45
49
 
46
- DETECTORS = [Bullet::Detector::NPlusOneQuery,
47
- Bullet::Detector::UnusedEagerLoading,
48
- Bullet::Detector::CounterCache].freeze
50
+ DETECTORS = [
51
+ Bullet::Detector::NPlusOneQuery,
52
+ Bullet::Detector::UnusedEagerLoading,
53
+ Bullet::Detector::CounterCache
54
+ ].freeze
49
55
 
50
56
  def enable=(enable)
51
57
  @enable = @n_plus_one_query_enable = @unused_eager_loading_enable = @counter_cache_enable = enable
58
+
52
59
  if enable?
53
- reset_whitelist
54
- unless orm_pathches_applied
55
- self.orm_pathches_applied = true
60
+ reset_safelist
61
+ unless orm_patches_applied
62
+ self.orm_patches_applied = true
56
63
  Bullet::Mongoid.enable if mongoid?
57
64
  Bullet::ActiveRecord.enable if active_record?
58
65
  end
@@ -63,6 +70,11 @@ module Bullet
63
70
  !!@enable
64
71
  end
65
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
+
66
78
  def n_plus_one_query_enable?
67
79
  enable? && !!@n_plus_one_query_enable
68
80
  end
@@ -76,51 +88,50 @@ module Bullet
76
88
  end
77
89
 
78
90
  def stacktrace_includes
79
- @stacktrace_includes || []
91
+ @stacktrace_includes ||= []
80
92
  end
81
93
 
82
94
  def stacktrace_excludes
83
- @stacktrace_excludes || []
95
+ @stacktrace_excludes ||= []
84
96
  end
85
97
 
86
- def add_whitelist(options)
87
- reset_whitelist
88
- @whitelist[options[:type]][options[:class_name]] ||= []
89
- @whitelist[options[:type]][options[:class_name]] << options[:association].to_sym
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
90
102
  end
91
103
 
92
- def delete_whitelist(options)
93
- 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? }
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? }
97
109
  end
98
110
 
99
- def get_whitelist_associations(type, class_name)
100
- Array(@whitelist[type][class_name])
111
+ def get_safelist_associations(type, class_name)
112
+ Array.wrap(@safelist[type][class_name])
101
113
  end
102
114
 
103
- def reset_whitelist
104
- @whitelist ||= { n_plus_one_query: {}, unused_eager_loading: {}, counter_cache: {} }
115
+ def reset_safelist
116
+ @safelist ||= { n_plus_one_query: {}, unused_eager_loading: {}, counter_cache: {} }
105
117
  end
106
118
 
107
- def clear_whitelist
108
- @whitelist = nil
119
+ def clear_safelist
120
+ @safelist = 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
120
131
  end
121
132
 
122
133
  def debug(title, message)
123
- puts "[Bullet][#{title}] #{message}" if ENV[BULLET_DEBUG] == TRUE
134
+ puts "[Bullet][#{title}] #{message}" if ENV['BULLET_DEBUG'] == 'true'
124
135
  end
125
136
 
126
137
  def start_request
@@ -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,16 @@ 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
+ return false if defined?(@skip_html_injection) && @skip_html_injection
244
+
245
+ console_enabled? || add_footer
246
+ end
247
+
222
248
  private
223
249
 
224
250
  def for_each_active_notifier_with_notification
@@ -10,17 +10,16 @@ module Bullet
10
10
 
11
11
  def enable_in_development
12
12
  environment(nil, env: 'development') do
13
- <<-"FILE".strip
14
-
15
- config.after_initialize do
16
- Bullet.enable = true
17
- Bullet.alert = true
18
- Bullet.bullet_logger = true
19
- Bullet.console = true
20
- # Bullet.growl = true
21
- Bullet.rails_logger = true
22
- Bullet.add_footer = true
23
- end
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.rails_logger = true
20
+ Bullet.add_footer = true
21
+ end
22
+
24
23
  FILE
25
24
  end
26
25
 
@@ -28,20 +27,20 @@ module Bullet
28
27
  end
29
28
 
30
29
  def enable_in_test
31
- if yes?('Would you like to enable bullet in test environment? (y/n)')
32
- environment(nil, env: 'test') do
33
- <<-"FILE".strip
34
-
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
- FILE
41
- end
30
+ return unless yes?('Would you like to enable bullet in test environment? (y/n)')
42
31
 
43
- say 'Enabled bullet in config/environments/test.rb'
32
+ environment(nil, env: 'test') do
33
+ <<~FILE
34
+ config.after_initialize do
35
+ Bullet.enable = true
36
+ Bullet.bullet_logger = true
37
+ Bullet.raise = true # raise an error if n+1 query occurs
38
+ end
39
+
40
+ FILE
44
41
  end
42
+
43
+ say 'Enabled bullet in config/environments/test.rb'
45
44
  end
46
45
  end
47
46
  end
data/perf/benchmark.rb CHANGED
@@ -29,11 +29,14 @@ class User < ActiveRecord::Base
29
29
  end
30
30
 
31
31
  # create database bullet_benchmark;
32
- ActiveRecord::Base.establish_connection(adapter: 'mysql2', database: 'bullet_benchmark', server: '/tmp/mysql.socket', username: 'root')
32
+ ActiveRecord::Base.establish_connection(
33
+ adapter: 'mysql2',
34
+ database: 'bullet_benchmark',
35
+ server: '/tmp/mysql.socket',
36
+ username: 'root'
37
+ )
33
38
 
34
- ActiveRecord::Base.connection.tables.each do |table|
35
- ActiveRecord::Base.connection.drop_table(table)
36
- end
39
+ ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
37
40
 
38
41
  ActiveRecord::Schema.define(version: 1) do
39
42
  create_table :posts do |t|
@@ -54,26 +57,20 @@ ActiveRecord::Schema.define(version: 1) do
54
57
  end
55
58
 
56
59
  users_size = 100
57
- posts_size = 1000
60
+ posts_size = 1_000
58
61
  comments_size = 10_000
59
62
  users = []
60
- users_size.times do |i|
61
- users << User.new(name: "user#{i}")
62
- end
63
+ users_size.times { |i| users << User.new(name: "user#{i}") }
63
64
  User.import users
64
65
  users = User.all
65
66
 
66
67
  posts = []
67
- posts_size.times do |i|
68
- posts << Post.new(title: "Title #{i}", body: "Body #{i}", user: users[i % 100])
69
- end
68
+ posts_size.times { |i| posts << Post.new(title: "Title #{i}", body: "Body #{i}", user: users[i % 100]) }
70
69
  Post.import posts
71
70
  posts = Post.all
72
71
 
73
72
  comments = []
74
- comments_size.times do |i|
75
- comments << Comment.new(body: "Comment #{i}", post: posts[i % 1000], user: users[i % 100])
76
- end
73
+ comments_size.times { |i| comments << Comment.new(body: "Comment #{i}", post: posts[i % 1_000], user: users[i % 100]) }
77
74
  Comment.import comments
78
75
 
79
76
  puts 'Start benchmarking...'
@@ -12,15 +12,15 @@ module Bullet
12
12
 
13
13
  context '.add_counter_cache' do
14
14
  it 'should create notification if conditions met' do
15
- expect(CounterCache).to receive(:conditions_met?).with(@post1, [:comments]).and_return(true)
16
- expect(CounterCache).to receive(:create_notification).with('Post', [:comments])
17
- CounterCache.add_counter_cache(@post1, [:comments])
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])
18
18
  end
19
19
 
20
20
  it 'should not create notification if conditions not met' do
21
- expect(CounterCache).to receive(:conditions_met?).with(@post1, [:comments]).and_return(false)
21
+ expect(CounterCache).to receive(:conditions_met?).with(@post1, %i[comments]).and_return(false)
22
22
  expect(CounterCache).to receive(:create_notification).never
23
- CounterCache.add_counter_cache(@post1, [:comments])
23
+ CounterCache.add_counter_cache(@post1, %i[comments])
24
24
  end
25
25
  end
26
26
 
@@ -47,7 +47,7 @@ module Bullet
47
47
  expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
48
48
  end
49
49
 
50
- it 'should be true when object is possible, and impossible' do
50
+ it 'should be false when object is possible, and impossible' do
51
51
  CounterCache.add_possible_objects(@post1)
52
52
  CounterCache.add_impossible_object(@post1)
53
53
  expect(CounterCache.conditions_met?(@post1, :associations)).to eq false
@@ -39,7 +39,7 @@ module Bullet
39
39
 
40
40
  it 'should be false if object, association pair is not existed' do
41
41
  NPlusOneQuery.add_object_associations(@post, :association1)
42
- expect(NPlusOneQuery.association?(@post, :associatio2)).to eq false
42
+ expect(NPlusOneQuery.association?(@post, :association2)).to eq false
43
43
  end
44
44
  end
45
45
 
@@ -76,8 +76,8 @@ module Bullet
76
76
  context '.call_association' do
77
77
  it 'should create notification if conditions met' do
78
78
  expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
79
- expect(NPlusOneQuery).to receive(:caller_in_project).and_return(['caller'])
80
- expect(NPlusOneQuery).to receive(:create_notification).with(['caller'], 'Post', :association)
79
+ expect(NPlusOneQuery).to receive(:caller_in_project).and_return(%w[caller])
80
+ expect(NPlusOneQuery).to receive(:create_notification).with(%w[caller], 'Post', :association)
81
81
  NPlusOneQuery.call_association(@post, :association)
82
82
  end
83
83
 
@@ -149,7 +149,11 @@ module Bullet
149
149
 
150
150
  expect(NPlusOneQuery).to receive(:caller_locations).and_return([in_project, *included_gems, excluded_gem])
151
151
  expect(NPlusOneQuery).to receive(:conditions_met?).with(@post, :association).and_return(true)
152
- expect(NPlusOneQuery).to receive(:create_notification).with([in_project, *included_gems], 'Post', :association)
152
+ expect(NPlusOneQuery).to receive(:create_notification).with(
153
+ [in_project, *included_gems],
154
+ 'Post',
155
+ :association
156
+ )
153
157
  NPlusOneQuery.call_association(@post, :association)
154
158
  end
155
159
  end
@@ -19,7 +19,9 @@ module Bullet
19
19
  it 'should get call associations if object and association are both in eager_loadings and call_object_associations' do
20
20
  UnusedEagerLoading.add_eager_loadings([@post], :association)
21
21
  UnusedEagerLoading.add_call_object_associations(@post, :association)
22
- expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to eq([:association])
22
+ expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to eq(
23
+ [:association]
24
+ )
23
25
  end
24
26
 
25
27
  it 'should not get call associations if not exist in call_object_associations' do
@@ -30,18 +32,22 @@ module Bullet
30
32
 
31
33
  context '.diff_object_associations' do
32
34
  it 'should return associations not exist in call_association' do
33
- expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to eq([:association])
35
+ expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to eq(
36
+ [:association]
37
+ )
34
38
  end
35
39
 
36
40
  it 'should return empty if associations exist in call_association' do
37
41
  UnusedEagerLoading.add_eager_loadings([@post], :association)
38
42
  UnusedEagerLoading.add_call_object_associations(@post, :association)
39
- expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to be_empty
43
+ expect(
44
+ UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))
45
+ ).to be_empty
40
46
  end
41
47
  end
42
48
 
43
49
  context '.check_unused_preload_associations' do
44
- let(:paths) { ['/dir1', '/dir1/subdir'] }
50
+ let(:paths) { %w[/dir1 /dir1/subdir] }
45
51
  it 'should create notification if object_association_diff is not empty' do
46
52
  UnusedEagerLoading.add_object_associations(@post, :association)
47
53
  allow(UnusedEagerLoading).to receive(:caller_in_project).and_return(paths)
@@ -53,7 +59,9 @@ module Bullet
53
59
  UnusedEagerLoading.add_object_associations(@post, :association)
54
60
  UnusedEagerLoading.add_eager_loadings([@post], :association)
55
61
  UnusedEagerLoading.add_call_object_associations(@post, :association)
56
- expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to be_empty
62
+ expect(
63
+ UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))
64
+ ).to be_empty
57
65
  expect(UnusedEagerLoading).not_to receive(:create_notification).with('Post', [:association])
58
66
  UnusedEagerLoading.check_unused_preload_associations
59
67
  end
@@ -62,14 +70,23 @@ module Bullet
62
70
  context '.add_eager_loadings' do
63
71
  it 'should add objects, associations pair when eager_loadings are empty' do
64
72
  UnusedEagerLoading.add_eager_loadings([@post, @post2], :associations)
65
- expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key, @post2.bullet_key], :associations)
73
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
74
+ [@post.bullet_key, @post2.bullet_key],
75
+ :associations
76
+ )
66
77
  end
67
78
 
68
79
  it 'should add objects, associations pair for existing eager_loadings' do
69
80
  UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
70
81
  UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
71
- expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key, @post2.bullet_key], :association1)
72
- expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key, @post2.bullet_key], :association2)
82
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
83
+ [@post.bullet_key, @post2.bullet_key],
84
+ :association1
85
+ )
86
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include(
87
+ [@post.bullet_key, @post2.bullet_key],
88
+ :association2
89
+ )
73
90
  end
74
91
 
75
92
  it 'should merge objects, associations pair for existing eager_loadings' do
@@ -10,30 +10,35 @@ describe Object do
10
10
  end
11
11
 
12
12
  if mongoid?
13
- it 'should return class with namesapce and id composition' do
13
+ it 'should return class with namespace and id composition' do
14
14
  post = Mongoid::Post.first
15
15
  expect(post.bullet_key).to eq("Mongoid::Post:#{post.id}")
16
16
  end
17
17
  end
18
18
  end
19
19
 
20
- context 'primary_key_value' do
20
+ context 'bullet_primary_key_value' do
21
21
  it 'should return id' do
22
22
  post = Post.first
23
- expect(post.primary_key_value).to eq(post.id)
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.primary_key_value).to eq(post.name)
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.primary_key_value).to eq("#{post.category_id},#{post.writer_id}")
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
@@ -26,9 +26,7 @@ module Bullet
26
26
  end
27
27
 
28
28
  it 'should leverage ENV parameter' do
29
- temp_env_variable('USER', 'bogus') do
30
- expect(subject.whoami).to eq('user: bogus')
31
- end
29
+ temp_env_variable('USER', 'bogus') { expect(subject.whoami).to eq('user: bogus') }
32
30
  end
33
31
 
34
32
  it 'should return blank if no user available' do
@@ -76,8 +74,8 @@ module Bullet
76
74
  it 'should send full_notice to notifier' do
77
75
  notifier = double
78
76
  allow(subject).to receive(:notifier).and_return(notifier)
79
- allow(subject).to receive(:notification_data).and_return(foo: :bar)
80
- expect(notifier).to receive(:inline_notify).with(foo: :bar)
77
+ allow(subject).to receive(:notification_data).and_return({ foo: :bar })
78
+ expect(notifier).to receive(:inline_notify).with({ foo: :bar })
81
79
  subject.notify_inline
82
80
  end
83
81
  end
@@ -86,8 +84,8 @@ module Bullet
86
84
  it 'should send full_out_of_channel to notifier' do
87
85
  notifier = double
88
86
  allow(subject).to receive(:notifier).and_return(notifier)
89
- allow(subject).to receive(:notification_data).and_return(foo: :bar)
90
- expect(notifier).to receive(:out_of_channel_notify).with(foo: :bar)
87
+ allow(subject).to receive(:notification_data).and_return({ foo: :bar })
88
+ expect(notifier).to receive(:out_of_channel_notify).with({ foo: :bar })
91
89
  subject.notify_out_of_channel
92
90
  end
93
91
  end
@@ -7,9 +7,22 @@ module Bullet
7
7
  describe NPlusOneQuery do
8
8
  subject { NPlusOneQuery.new([%w[caller1 caller2]], Post, %i[comments votes], 'path') }
9
9
 
10
- it { expect(subject.body_with_caller).to eq(" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n") }
11
- it { expect([subject.body_with_caller, subject.body_with_caller]).to eq([" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n", " Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nCall stack\n caller1\n caller2\n"]) }
12
- it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]") }
10
+ it do
11
+ expect(subject.body_with_caller).to eq(
12
+ " Post => [:comments, :votes]\n Add to your query: .includes([:comments, :votes])\nCall stack\n caller1\n caller2\n"
13
+ )
14
+ end
15
+ it do
16
+ expect([subject.body_with_caller, subject.body_with_caller]).to eq(
17
+ [
18
+ " Post => [:comments, :votes]\n Add to your query: .includes([:comments, :votes])\nCall stack\n caller1\n caller2\n",
19
+ " Post => [:comments, :votes]\n Add to your query: .includes([:comments, :votes])\nCall stack\n caller1\n caller2\n"
20
+ ]
21
+ )
22
+ end
23
+ it do
24
+ expect(subject.body).to eq(" Post => [:comments, :votes]\n Add to your query: .includes([:comments, :votes])")
25
+ end
13
26
  it { expect(subject.title).to eq('USE eager loading in path') }
14
27
  end
15
28
  end
@@ -7,7 +7,11 @@ module Bullet
7
7
  describe UnusedEagerLoading do
8
8
  subject { UnusedEagerLoading.new([''], Post, %i[comments votes], 'path') }
9
9
 
10
- it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Remove from your finder: :includes => [:comments, :votes]") }
10
+ it do
11
+ expect(subject.body).to eq(
12
+ " Post => [:comments, :votes]\n Remove from your query: .includes([:comments, :votes])"
13
+ )
14
+ end
11
15
  it { expect(subject.title).to eq('AVOID eager loading in path') }
12
16
  end
13
17
  end