bullet 6.0.2 → 6.1.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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -1
  3. data/CHANGELOG.md +25 -0
  4. data/Gemfile.rails-6.0 +1 -1
  5. data/Gemfile.rails-6.1 +15 -0
  6. data/README.md +12 -2
  7. data/lib/bullet.rb +31 -20
  8. data/lib/bullet/active_job.rb +1 -3
  9. data/lib/bullet/active_record4.rb +9 -23
  10. data/lib/bullet/active_record41.rb +7 -19
  11. data/lib/bullet/active_record42.rb +8 -16
  12. data/lib/bullet/active_record5.rb +188 -170
  13. data/lib/bullet/active_record52.rb +187 -161
  14. data/lib/bullet/active_record60.rb +194 -175
  15. data/lib/bullet/active_record61.rb +278 -0
  16. data/lib/bullet/bullet_xhr.js +17 -23
  17. data/lib/bullet/dependency.rb +42 -34
  18. data/lib/bullet/detector/association.rb +24 -18
  19. data/lib/bullet/detector/base.rb +1 -2
  20. data/lib/bullet/detector/counter_cache.rb +10 -6
  21. data/lib/bullet/detector/n_plus_one_query.rb +18 -8
  22. data/lib/bullet/detector/unused_eager_loading.rb +5 -2
  23. data/lib/bullet/mongoid4x.rb +3 -7
  24. data/lib/bullet/mongoid5x.rb +3 -7
  25. data/lib/bullet/mongoid6x.rb +3 -7
  26. data/lib/bullet/mongoid7x.rb +3 -7
  27. data/lib/bullet/notification/base.rb +14 -18
  28. data/lib/bullet/notification/n_plus_one_query.rb +2 -4
  29. data/lib/bullet/notification/unused_eager_loading.rb +2 -4
  30. data/lib/bullet/rack.rb +23 -15
  31. data/lib/bullet/stack_trace_filter.rb +7 -16
  32. data/lib/bullet/version.rb +1 -1
  33. data/lib/generators/bullet/install_generator.rb +23 -23
  34. data/perf/benchmark.rb +8 -14
  35. data/spec/bullet/detector/counter_cache_spec.rb +6 -6
  36. data/spec/bullet/detector/n_plus_one_query_spec.rb +7 -3
  37. data/spec/bullet/detector/unused_eager_loading_spec.rb +19 -6
  38. data/spec/bullet/notification/base_spec.rb +1 -3
  39. data/spec/bullet/notification/n_plus_one_query_spec.rb +16 -3
  40. data/spec/bullet/notification/unused_eager_loading_spec.rb +5 -1
  41. data/spec/bullet/rack_spec.rb +133 -7
  42. data/spec/bullet/registry/association_spec.rb +2 -2
  43. data/spec/bullet/registry/base_spec.rb +1 -1
  44. data/spec/bullet_spec.rb +10 -29
  45. data/spec/integration/active_record/association_spec.rb +77 -122
  46. data/spec/integration/counter_cache_spec.rb +10 -30
  47. data/spec/integration/mongoid/association_spec.rb +18 -32
  48. data/spec/models/attachment.rb +5 -0
  49. data/spec/models/folder.rb +1 -2
  50. data/spec/models/group.rb +1 -2
  51. data/spec/models/page.rb +1 -2
  52. data/spec/models/submission.rb +1 -0
  53. data/spec/models/user.rb +1 -0
  54. data/spec/models/writer.rb +1 -2
  55. data/spec/spec_helper.rb +6 -10
  56. data/spec/support/bullet_ext.rb +8 -9
  57. data/spec/support/mongo_seed.rb +2 -16
  58. data/spec/support/sqlite_seed.rb +8 -0
  59. metadata +10 -6
@@ -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
@@ -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
@@ -67,12 +67,12 @@ module Bullet
67
67
 
68
68
  it 'should change response body if notification is active' do
69
69
  expect(Bullet).to receive(:notification?).and_return(true)
70
+ expect(Bullet).to receive(:console_enabled?).and_return(true)
70
71
  expect(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
71
- expect(middleware).to receive(:xhr_script).and_return('')
72
72
  expect(Bullet).to receive(:perform_out_of_channel_notifications)
73
- status, headers, response = middleware.call('Content-Type' => 'text/html')
73
+ _, headers, response = middleware.call('Content-Type' => 'text/html')
74
74
  expect(headers['Content-Length']).to eq('56')
75
- expect(response).to eq(['<html><head></head><body><bullet></bullet></body></html>'])
75
+ expect(response).to eq(%w[<html><head></head><body><bullet></bullet></body></html>])
76
76
  end
77
77
 
78
78
  it 'should set the right Content-Length if response body contains accents' do
@@ -80,9 +80,135 @@ module Bullet
80
80
  response.body = '<html><head></head><body>é</body></html>'
81
81
  app.response = response
82
82
  expect(Bullet).to receive(:notification?).and_return(true)
83
+ allow(Bullet).to receive(:console_enabled?).and_return(true)
83
84
  expect(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
84
- status, headers, response = middleware.call('Content-Type' => 'text/html')
85
- expect(headers['Content-Length']).to eq((58 + middleware.send(:xhr_script).length).to_s)
85
+ _, headers, response = middleware.call('Content-Type' => 'text/html')
86
+ expect(headers['Content-Length']).to eq('58')
87
+ end
88
+
89
+ context 'with injection notifiers' do
90
+ before do
91
+ expect(Bullet).to receive(:notification?).and_return(true)
92
+ allow(Bullet).to receive(:gather_inline_notifications).and_return('<bullet></bullet>')
93
+ allow(middleware).to receive(:xhr_script).and_return('<script></script>')
94
+ allow(middleware).to receive(:footer_note).and_return('footer')
95
+ expect(Bullet).to receive(:perform_out_of_channel_notifications)
96
+ end
97
+
98
+ it 'should change response body if add_footer is true' do
99
+ expect(Bullet).to receive(:add_footer).exactly(3).times.and_return(true)
100
+ _, headers, response = middleware.call('Content-Type' => 'text/html')
101
+
102
+ expect(headers['Content-Length']).to eq((73 + middleware.send(:footer_note).length).to_s)
103
+ expect(response).to eq(%w[<html><head></head><body>footer<bullet></bullet><script></script></body></html>])
104
+ end
105
+
106
+ it 'should change response body for html safe string if add_footer is true' do
107
+ expect(Bullet).to receive(:add_footer).exactly(3).times.and_return(true)
108
+ app.response = Support::ResponseDouble.new.tap do |response|
109
+ response.body = ActiveSupport::SafeBuffer.new('<html><head></head><body></body></html>')
110
+ end
111
+ _, headers, response = middleware.call('Content-Type' => 'text/html')
112
+
113
+ expect(headers['Content-Length']).to eq((73 + middleware.send(:footer_note).length).to_s)
114
+ expect(response).to eq(%w[<html><head></head><body>footer<bullet></bullet><script></script></body></html>])
115
+ end
116
+
117
+ it 'should add the footer-text header for non-html requests when add_footer is true' do
118
+ allow(Bullet).to receive(:add_footer).at_least(:once).and_return(true)
119
+ allow(Bullet).to receive(:footer_info).and_return(['footer text'])
120
+ app.headers = {'Content-Type' => 'application/json'}
121
+ _, headers, _response = middleware.call({})
122
+ expect(headers).to include('X-bullet-footer-text' => '["footer text"]')
123
+ end
124
+
125
+ it 'should change response body if console_enabled is true' do
126
+ expect(Bullet).to receive(:console_enabled?).and_return(true)
127
+ _, headers, response = middleware.call('Content-Type' => 'text/html')
128
+ expect(headers['Content-Length']).to eq('56')
129
+ expect(response).to eq(%w[<html><head></head><body><bullet></bullet></body></html>])
130
+ end
131
+
132
+ it 'should change response body for html safe string if console_enabled is true' do
133
+ expect(Bullet).to receive(:console_enabled?).and_return(true)
134
+ app.response = Support::ResponseDouble.new.tap do |response|
135
+ response.body = ActiveSupport::SafeBuffer.new('<html><head></head><body></body></html>')
136
+ end
137
+ _, headers, response = middleware.call('Content-Type' => 'text/html')
138
+ expect(headers['Content-Length']).to eq('56')
139
+ expect(response).to eq(%w[<html><head></head><body><bullet></bullet></body></html>])
140
+ end
141
+
142
+ it 'should add headers for non-html requests when console_enabled is true' do
143
+ allow(Bullet).to receive(:console_enabled?).at_least(:once).and_return(true)
144
+ allow(Bullet).to receive(:text_notifications).and_return(['text notifications'])
145
+ app.headers = {'Content-Type' => 'application/json'}
146
+ _, headers, _response = middleware.call({})
147
+ expect(headers).to include('X-bullet-console-text' => '["text notifications"]')
148
+ end
149
+
150
+ it "shouldn't change response body unnecessarily" do
151
+ expected_response = Support::ResponseDouble.new 'Actual body'
152
+ app.response = expected_response
153
+ _, _, response = middleware.call({})
154
+ expect(response).to eq(expected_response)
155
+ end
156
+
157
+ it "shouldn't add headers unnecessarily" do
158
+ app.headers = {'Content-Type' => 'application/json'}
159
+ _, headers, _response = middleware.call({})
160
+ expect(headers).not_to include('X-bullet-footer-text')
161
+ expect(headers).not_to include('X-bullet-console-text')
162
+ end
163
+
164
+ context "when skip_http_headers is enabled" do
165
+ before do
166
+ allow(Bullet).to receive(:skip_http_headers).and_return(true)
167
+ end
168
+
169
+ it 'should include the footer but not the xhr script tag if add_footer is true' do
170
+ expect(Bullet).to receive(:add_footer).at_least(:once).and_return(true)
171
+ _, headers, response = middleware.call({})
172
+
173
+ expect(headers['Content-Length']).to eq((56 + middleware.send(:footer_note).length).to_s)
174
+ expect(response).to eq(%w[<html><head></head><body>footer<bullet></bullet></body></html>])
175
+ end
176
+
177
+ it 'should not include the xhr script tag if console_enabled is true' do
178
+ expect(Bullet).to receive(:console_enabled?).and_return(true)
179
+ _, headers, response = middleware.call({})
180
+ expect(headers['Content-Length']).to eq('56')
181
+ expect(response).to eq(%w[<html><head></head><body><bullet></bullet></body></html>])
182
+ end
183
+
184
+ it 'should not add the footer-text header for non-html requests when add_footer is true' do
185
+ allow(Bullet).to receive(:add_footer).at_least(:once).and_return(true)
186
+ app.headers = {'Content-Type' => 'application/json'}
187
+ _, headers, _response = middleware.call({})
188
+ expect(headers).not_to include('X-bullet-footer-text')
189
+ end
190
+
191
+ it 'should not add headers for non-html requests when console_enabled is true' do
192
+ allow(Bullet).to receive(:console_enabled?).at_least(:once).and_return(true)
193
+ app.headers = {'Content-Type' => 'application/json'}
194
+ _, headers, _response = middleware.call({})
195
+ expect(headers).not_to include('X-bullet-console-text')
196
+ end
197
+ end
198
+ end
199
+
200
+ context 'when skip_html_injection is enabled' do
201
+ it 'should not try to inject html' do
202
+ expected_response = Support::ResponseDouble.new 'Actual body'
203
+ app.response = expected_response
204
+ allow(Bullet).to receive(:notification?).and_return(true)
205
+ allow(Bullet).to receive(:skip_html_injection?).and_return(true)
206
+ expect(Bullet).to receive(:gather_inline_notifications).never
207
+ expect(middleware).to receive(:xhr_script).never
208
+ expect(Bullet).to receive(:perform_out_of_channel_notifications)
209
+ _, _, response = middleware.call('Content-Type' => 'text/html')
210
+ expect(response).to eq(expected_response)
211
+ end
86
212
  end
87
213
  end
88
214
 
@@ -98,8 +224,8 @@ module Bullet
98
224
 
99
225
  context '#set_header' do
100
226
  it 'should truncate headers to under 8kb' do
101
- long_header = ['a' * 1024] * 10
102
- expected_res = (['a' * 1024] * 7).to_json
227
+ long_header = ['a' * 1_024] * 10
228
+ expected_res = (['a' * 1_024] * 7).to_json
103
229
  expect(middleware.set_header({}, 'Dummy-Header', long_header)).to eq(expected_res)
104
230
  end
105
231
  end
@@ -16,11 +16,11 @@ module Bullet
16
16
 
17
17
  context '#similarly_associated' do
18
18
  it 'should return similarly associated keys' do
19
- expect(subject.similarly_associated('key1', Set.new(['value']))).to eq(%w[key1 key2])
19
+ expect(subject.similarly_associated('key1', Set.new(%w[value]))).to eq(%w[key1 key2])
20
20
  end
21
21
 
22
22
  it 'should return empty if key does not exist' do
23
- expect(subject.similarly_associated('key3', Set.new(['value']))).to be_empty
23
+ expect(subject.similarly_associated('key3', Set.new(%w[value]))).to be_empty
24
24
  end
25
25
  end
26
26
  end
@@ -9,7 +9,7 @@ module Bullet
9
9
 
10
10
  context '#[]' do
11
11
  it 'should get value by key' do
12
- expect(subject['key']).to eq(Set.new(['value']))
12
+ expect(subject['key']).to eq(Set.new(%w[value]))
13
13
  end
14
14
  end
15
15
 
data/spec/bullet_spec.rb CHANGED
@@ -17,9 +17,7 @@ describe Bullet, focused: true do
17
17
  end
18
18
 
19
19
  context 'disable Bullet' do
20
- before do
21
- Bullet.enable = false
22
- end
20
+ before { Bullet.enable = false }
23
21
 
24
22
  it 'should be disabled' do
25
23
  expect(subject).to_not be_enable
@@ -27,8 +25,8 @@ describe Bullet, focused: true do
27
25
 
28
26
  context 'enable Bullet again without patching again the orms' do
29
27
  before do
30
- expect(Bullet::Mongoid).not_to receive(:enable) if defined? Bullet::Mongoid
31
- expect(Bullet::ActiveRecord).not_to receive(:enable) if defined? Bullet::ActiveRecord
28
+ expect(Bullet::Mongoid).not_to receive(:enable) if defined?(Bullet::Mongoid)
29
+ expect(Bullet::ActiveRecord).not_to receive(:enable) if defined?(Bullet::ActiveRecord)
32
30
  Bullet.enable = true
33
31
  end
34
32
 
@@ -42,9 +40,7 @@ describe Bullet, focused: true do
42
40
 
43
41
  describe '#start?' do
44
42
  context 'when bullet is disabled' do
45
- before(:each) do
46
- Bullet.enable = false
47
- end
43
+ before(:each) { Bullet.enable = false }
48
44
 
49
45
  it 'should not be started' do
50
46
  expect(Bullet).not_to be_start
@@ -53,28 +49,19 @@ describe Bullet, focused: true do
53
49
  end
54
50
 
55
51
  describe '#debug' do
56
- before(:each) do
57
- $stdout = StringIO.new
58
- end
52
+ before(:each) { $stdout = StringIO.new }
59
53
 
60
- after(:each) do
61
- $stdout = STDOUT
62
- end
54
+ after(:each) { $stdout = STDOUT }
63
55
 
64
56
  context 'when debug is enabled' do
65
- before(:each) do
66
- ENV['BULLET_DEBUG'] = 'true'
67
- end
57
+ before(:each) { ENV['BULLET_DEBUG'] = 'true' }
68
58
 
69
- after(:each) do
70
- ENV['BULLET_DEBUG'] = 'false'
71
- end
59
+ after(:each) { ENV['BULLET_DEBUG'] = 'false' }
72
60
 
73
61
  it 'should output debug information' do
74
62
  Bullet.debug('debug_message', 'this is helpful information')
75
63
 
76
- expect($stdout.string)
77
- .to eq("[Bullet][debug_message] this is helpful information\n")
64
+ expect($stdout.string).to eq("[Bullet][debug_message] this is helpful information\n")
78
65
  end
79
66
  end
80
67
 
@@ -125,13 +112,7 @@ describe Bullet, focused: true do
125
112
  end
126
113
 
127
114
  context 'when called with Rack environment hash' do
128
- let(:env) {
129
- {
130
- 'REQUEST_METHOD' => 'GET',
131
- 'PATH_INFO' => '/path',
132
- 'QUERY_STRING' => 'foo=bar'
133
- }
134
- }
115
+ let(:env) { { 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/path', 'QUERY_STRING' => 'foo=bar' } }
135
116
 
136
117
  context "when env['REQUEST_URI'] is nil" do
137
118
  before { env['REQUEST_URI'] = nil }
@@ -6,9 +6,7 @@ if active_record?
6
6
  describe Bullet::Detector::Association, 'has_many' do
7
7
  context 'post => comments' do
8
8
  it 'should detect non preload post => comments' do
9
- Post.all.each do |post|
10
- post.comments.map(&:name)
11
- end
9
+ Post.all.each { |post| post.comments.map(&:name) }
12
10
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
13
11
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
14
12
 
@@ -16,9 +14,7 @@ if active_record?
16
14
  end
17
15
 
18
16
  it 'should detect non preload post => comments for find_by_sql' do
19
- Post.find_by_sql('SELECT * FROM posts').each do |post|
20
- post.comments.map(&:name)
21
- end
17
+ Post.find_by_sql('SELECT * FROM posts').each { |post| post.comments.map(&:name) }
22
18
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
23
19
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
24
20
 
@@ -26,9 +22,7 @@ if active_record?
26
22
  end
27
23
 
28
24
  it 'should detect preload with post => comments' do
29
- Post.includes(:comments).each do |post|
30
- post.comments.map(&:name)
31
- end
25
+ Post.includes(:comments).each { |post| post.comments.map(&:name) }
32
26
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
33
27
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
34
28
 
@@ -65,9 +59,7 @@ if active_record?
65
59
  end
66
60
 
67
61
  it 'should detect non preload post => comments with empty?' do
68
- Post.all.each do |post|
69
- post.comments.empty?
70
- end
62
+ Post.all.each { |post| post.comments.empty? }
71
63
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
72
64
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
73
65
 
@@ -76,9 +68,7 @@ if active_record?
76
68
 
77
69
  it 'should detect non preload post => comments with include?' do
78
70
  comment = Comment.last
79
- Post.all.each do |post|
80
- post.comments.include?(comment)
81
- end
71
+ Post.all.each { |post| post.comments.include?(comment) }
82
72
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
83
73
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
84
74
 
@@ -86,9 +76,7 @@ if active_record?
86
76
  end
87
77
 
88
78
  it 'should not detect unused preload person => pets with empty?' do
89
- Person.all.each do |person|
90
- person.pets.empty?
91
- end
79
+ Person.all.each { |person| person.pets.empty? }
92
80
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
93
81
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
94
82
 
@@ -98,11 +86,7 @@ if active_record?
98
86
 
99
87
  context 'category => posts => comments' do
100
88
  it 'should detect non preload category => posts => comments' do
101
- Category.all.each do |category|
102
- category.posts.each do |post|
103
- post.comments.map(&:name)
104
- end
105
- end
89
+ Category.all.each { |category| category.posts.each { |post| post.comments.map(&:name) } }
106
90
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
107
91
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
108
92
 
@@ -111,11 +95,7 @@ if active_record?
111
95
  end
112
96
 
113
97
  it 'should detect preload category => posts, but no post => comments' do
114
- Category.includes(:posts).each do |category|
115
- category.posts.each do |post|
116
- post.comments.map(&:name)
117
- end
118
- end
98
+ Category.includes(:posts).each { |category| category.posts.each { |post| post.comments.map(&:name) } }
119
99
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
120
100
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
121
101
 
@@ -124,11 +104,7 @@ if active_record?
124
104
  end
125
105
 
126
106
  it 'should detect preload with category => posts => comments' do
127
- Category.includes(posts: :comments).each do |category|
128
- category.posts.each do |post|
129
- post.comments.map(&:name)
130
- end
131
- end
107
+ Category.includes(posts: :comments).each { |category| category.posts.each { |post| post.comments.map(&:name) } }
132
108
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
133
109
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
134
110
 
@@ -137,9 +113,7 @@ if active_record?
137
113
 
138
114
  it 'should detect preload with category => posts => comments with posts.id > 0' do
139
115
  Category.includes(posts: :comments).where('posts.id > 0').references(:posts).each do |category|
140
- category.posts.each do |post|
141
- post.comments.map(&:name)
142
- end
116
+ category.posts.each { |post| post.comments.map(&:name) }
143
117
  end
144
118
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
145
119
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
@@ -156,9 +130,7 @@ if active_record?
156
130
  end
157
131
 
158
132
  it 'should detect unused preload with post => commnets, no category => posts' do
159
- Category.includes(posts: :comments).each do |category|
160
- category.posts.map(&:name)
161
- end
133
+ Category.includes(posts: :comments).each { |category| category.posts.map(&:name) }
162
134
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
163
135
  expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Post, :comments)
164
136
 
@@ -212,9 +184,7 @@ if active_record?
212
184
  end
213
185
 
214
186
  it 'should detect unused preload with category => entries, but not with category => posts' do
215
- Category.includes(%i[posts entries]).each do |category|
216
- category.posts.map(&:name)
217
- end
187
+ Category.includes(%i[posts entries]).each { |category| category.posts.map(&:name) }
218
188
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
219
189
  expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Category, :posts)
220
190
  expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Category, :entries)
@@ -225,9 +195,7 @@ if active_record?
225
195
 
226
196
  context 'post => comment' do
227
197
  it 'should detect unused preload with post => comments' do
228
- Post.includes(:comments).each do |post|
229
- post.comments.first&.name
230
- end
198
+ Post.includes(:comments).each { |post| post.comments.first&.name }
231
199
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
232
200
  expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :comments)
233
201
 
@@ -272,9 +240,7 @@ if active_record?
272
240
 
273
241
  context 'scope for_category_name' do
274
242
  it 'should detect preload with post => category' do
275
- Post.in_category_name('first').references(:categories).each do |post|
276
- post.category.name
277
- end
243
+ Post.in_category_name('first').references(:categories).each { |post| post.category.name }
278
244
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
279
245
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
280
246
 
@@ -292,9 +258,7 @@ if active_record?
292
258
 
293
259
  context 'scope preload_comments' do
294
260
  it 'should detect preload post => comments with scope' do
295
- Post.preload_comments.each do |post|
296
- post.comments.map(&:name)
297
- end
261
+ Post.preload_comments.each { |post| post.comments.map(&:name) }
298
262
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
299
263
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
300
264
 
@@ -314,9 +278,7 @@ if active_record?
314
278
  describe Bullet::Detector::Association, 'belongs_to' do
315
279
  context 'comment => post' do
316
280
  it 'should detect non preload with comment => post' do
317
- Comment.all.each do |comment|
318
- comment.post.name
319
- end
281
+ Comment.all.each { |comment| comment.post.name }
320
282
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
321
283
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
322
284
 
@@ -332,9 +294,7 @@ if active_record?
332
294
  end
333
295
 
334
296
  it 'should detect preload with comment => post' do
335
- Comment.includes(:post).each do |comment|
336
- comment.post.name
337
- end
297
+ Comment.includes(:post).each { |comment| comment.post.name }
338
298
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
339
299
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
340
300
 
@@ -371,9 +331,7 @@ if active_record?
371
331
 
372
332
  context 'comment => post => category' do
373
333
  it 'should detect non preload association with comment => post' do
374
- Comment.all.each do |comment|
375
- comment.post.category.name
376
- end
334
+ Comment.all.each { |comment| comment.post.category.name }
377
335
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
378
336
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
379
337
 
@@ -390,9 +348,7 @@ if active_record?
390
348
  end
391
349
 
392
350
  it 'should detect non preload association with post => category' do
393
- Comment.includes(:post).each do |comment|
394
- comment.post.category.name
395
- end
351
+ Comment.includes(:post).each { |comment| comment.post.category.name }
396
352
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
397
353
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
398
354
 
@@ -400,9 +356,7 @@ if active_record?
400
356
  end
401
357
 
402
358
  it 'should not detect unpreload association' do
403
- Comment.includes(post: :category).each do |comment|
404
- comment.post.category.name
405
- end
359
+ Comment.includes(post: :category).each { |comment| comment.post.category.name }
406
360
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
407
361
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
408
362
 
@@ -412,9 +366,8 @@ if active_record?
412
366
 
413
367
  context 'comment => author, post => writer' do
414
368
  it 'should detect non preloaded writer' do
415
- Comment.includes(%i[author post]).where(['base_users.id = ?', BaseUser.first]).references(:base_users).each do |comment|
416
- comment.post.writer.name
417
- end
369
+ Comment.includes(%i[author post]).where(['base_users.id = ?', BaseUser.first]).references(:base_users)
370
+ .each { |comment| comment.post.writer.name }
418
371
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
419
372
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
420
373
 
@@ -422,9 +375,9 @@ if active_record?
422
375
  end
423
376
 
424
377
  it 'should detect unused preload with comment => author' do
425
- Comment.includes([:author, { post: :writer }]).where(['base_users.id = ?', BaseUser.first]).references(:base_users).each do |comment|
426
- comment.post.writer.name
427
- end
378
+ Comment.includes([:author, { post: :writer }]).where(['base_users.id = ?', BaseUser.first]).references(
379
+ :base_users
380
+ ).each { |comment| comment.post.writer.name }
428
381
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
429
382
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
430
383
 
@@ -442,11 +395,7 @@ if active_record?
442
395
  end
443
396
 
444
397
  it 'should not raise a stack error from posts to category' do
445
- expect {
446
- Comment.includes(post: :category).each do |com|
447
- com.post.category
448
- end
449
- }.not_to raise_error
398
+ expect { Comment.includes(post: :category).each { |com| com.post.category } }.not_to raise_error
450
399
  end
451
400
  end
452
401
  end
@@ -454,9 +403,7 @@ if active_record?
454
403
  describe Bullet::Detector::Association, 'has_and_belongs_to_many' do
455
404
  context 'students <=> teachers' do
456
405
  it 'should detect non preload associations' do
457
- Student.all.each do |student|
458
- student.teachers.map(&:name)
459
- end
406
+ Student.all.each { |student| student.teachers.map(&:name) }
460
407
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
461
408
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
462
409
 
@@ -464,9 +411,7 @@ if active_record?
464
411
  end
465
412
 
466
413
  it 'should detect preload associations' do
467
- Student.includes(:teachers).each do |student|
468
- student.teachers.map(&:name)
469
- end
414
+ Student.includes(:teachers).each { |student| student.teachers.map(&:name) }
470
415
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
471
416
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
472
417
 
@@ -490,9 +435,7 @@ if active_record?
490
435
  end
491
436
 
492
437
  it 'should detect non preload student => teachers with empty?' do
493
- Student.all.each do |student|
494
- student.teachers.empty?
495
- end
438
+ Student.all.each { |student| student.teachers.empty? }
496
439
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
497
440
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
498
441
 
@@ -504,9 +447,7 @@ if active_record?
504
447
  describe Bullet::Detector::Association, 'has_many :through' do
505
448
  context 'firm => clients' do
506
449
  it 'should detect non preload associations' do
507
- Firm.all.each do |firm|
508
- firm.clients.map(&:name)
509
- end
450
+ Firm.all.each { |firm| firm.clients.map(&:name) }
510
451
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
511
452
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
512
453
 
@@ -514,9 +455,7 @@ if active_record?
514
455
  end
515
456
 
516
457
  it 'should detect preload associations' do
517
- Firm.includes(:clients).each do |firm|
518
- firm.clients.map(&:name)
519
- end
458
+ Firm.includes(:clients).each { |firm| firm.clients.map(&:name) }
520
459
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
521
460
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
522
461
 
@@ -542,9 +481,7 @@ if active_record?
542
481
 
543
482
  context 'firm => clients => groups' do
544
483
  it 'should detect non preload associations' do
545
- Firm.all.each do |firm|
546
- firm.groups.map(&:name)
547
- end
484
+ Firm.all.each { |firm| firm.groups.map(&:name) }
548
485
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
549
486
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
550
487
 
@@ -552,9 +489,7 @@ if active_record?
552
489
  end
553
490
 
554
491
  it 'should detect preload associations' do
555
- Firm.includes(:groups).each do |firm|
556
- firm.groups.map(&:name)
557
- end
492
+ Firm.includes(:groups).each { |firm| firm.groups.map(&:name) }
558
493
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
559
494
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
560
495
 
@@ -582,9 +517,7 @@ if active_record?
582
517
  describe Bullet::Detector::Association, 'has_one' do
583
518
  context 'company => address' do
584
519
  it 'should detect non preload association' do
585
- Company.all.each do |company|
586
- company.address.name
587
- end
520
+ Company.all.each { |company| company.address.name }
588
521
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
589
522
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
590
523
 
@@ -592,9 +525,7 @@ if active_record?
592
525
  end
593
526
 
594
527
  it 'should detect preload association' do
595
- Company.includes(:address).each do |company|
596
- company.address.name
597
- end
528
+ Company.includes(:address).each { |company| company.address.name }
598
529
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
599
530
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
600
531
 
@@ -630,6 +561,42 @@ if active_record?
630
561
  end
631
562
  end
632
563
 
564
+ describe Bullet::Detector::Association, 'has_one :through' do
565
+ context 'user => attachment' do
566
+ it 'should detect non preload associations' do
567
+ User.all.each { |user| user.submission_attachment.file_name }
568
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
569
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
570
+
571
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(User, :submission_attachment)
572
+ end
573
+
574
+ it 'should detect preload associations' do
575
+ User.includes(:submission_attachment).each { |user| user.submission_attachment.file_name }
576
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
577
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
578
+
579
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
580
+ end
581
+
582
+ it 'should not detect preload associations' do
583
+ User.all.map(&:name)
584
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
585
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
586
+
587
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
588
+ end
589
+
590
+ it 'should detect unused preload associations' do
591
+ User.includes(:submission_attachment).map(&:name)
592
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
593
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(User, :submission_attachment)
594
+
595
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
596
+ end
597
+ end
598
+ end
599
+
633
600
  describe Bullet::Detector::Association, 'call one association that in possible objects' do
634
601
  it 'should not detect preload association' do
635
602
  Post.all
@@ -688,9 +655,7 @@ if active_record?
688
655
  describe Bullet::Detector::Association, 'STI' do
689
656
  context 'page => author' do
690
657
  it 'should detect non preload associations' do
691
- Page.all.each do |page|
692
- page.author.name
693
- end
658
+ Page.all.each { |page| page.author.name }
694
659
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
695
660
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
696
661
 
@@ -698,9 +663,7 @@ if active_record?
698
663
  end
699
664
 
700
665
  it 'should detect preload associations' do
701
- Page.includes(:author).each do |page|
702
- page.author.name
703
- end
666
+ Page.includes(:author).each { |page| page.author.name }
704
667
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
705
668
  expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
706
669
 
@@ -729,9 +692,7 @@ if active_record?
729
692
  after { Bullet.n_plus_one_query_enable = true }
730
693
 
731
694
  it 'should not detect n plus one query' do
732
- Post.all.each do |post|
733
- post.comments.map(&:name)
734
- end
695
+ Post.all.each { |post| post.comments.map(&:name) }
735
696
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
736
697
 
737
698
  expect(Bullet::Detector::Association).not_to be_detecting_unpreloaded_association_for(Post, :comments)
@@ -760,9 +721,7 @@ if active_record?
760
721
  end
761
722
 
762
723
  it 'should still detect n plus one query' do
763
- Post.all.each do |post|
764
- post.comments.map(&:name)
765
- end
724
+ Post.all.each { |post| post.comments.map(&:name) }
766
725
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
767
726
 
768
727
  expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
@@ -775,9 +734,7 @@ if active_record?
775
734
  after { Bullet.clear_whitelist }
776
735
 
777
736
  it 'should not detect n plus one query' do
778
- Post.all.each do |post|
779
- post.comments.map(&:name)
780
- end
737
+ Post.all.each { |post| post.comments.map(&:name) }
781
738
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
782
739
 
783
740
  expect(Bullet::Detector::Association).not_to be_detecting_unpreloaded_association_for(Post, :comments)
@@ -806,9 +763,7 @@ if active_record?
806
763
  end
807
764
 
808
765
  it 'should still detect n plus one query' do
809
- Post.all.each do |post|
810
- post.comments.map(&:name)
811
- end
766
+ Post.all.each { |post| post.comments.map(&:name) }
812
767
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
813
768
 
814
769
  expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)