bullet 5.0.0 → 5.2.0

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +44 -13
  3. data/CHANGELOG.md +14 -32
  4. data/Gemfile.mongoid-2.4 +0 -2
  5. data/Gemfile.mongoid-2.5 +0 -2
  6. data/Gemfile.mongoid-2.6 +0 -2
  7. data/Gemfile.mongoid-2.7 +0 -2
  8. data/Gemfile.mongoid-2.8 +0 -2
  9. data/Gemfile.mongoid-3.0 +0 -2
  10. data/Gemfile.mongoid-3.1 +0 -2
  11. data/Gemfile.mongoid-4.0 +0 -2
  12. data/Gemfile.mongoid-5.0 +1 -3
  13. data/Gemfile.rails-3.0 +1 -2
  14. data/Gemfile.rails-3.1 +1 -2
  15. data/Gemfile.rails-3.2 +1 -2
  16. data/Gemfile.rails-4.0 +1 -2
  17. data/Gemfile.rails-4.1 +1 -2
  18. data/Gemfile.rails-4.2 +1 -2
  19. data/Gemfile.rails-5.0 +1 -3
  20. data/Hacking.md +1 -0
  21. data/README.md +5 -4
  22. data/bullet.gemspec +1 -1
  23. data/lib/bullet/active_record3.rb +34 -4
  24. data/lib/bullet/active_record3x.rb +34 -4
  25. data/lib/bullet/active_record4.rb +24 -4
  26. data/lib/bullet/active_record41.rb +9 -1
  27. data/lib/bullet/active_record42.rb +13 -3
  28. data/lib/bullet/active_record5.rb +55 -54
  29. data/lib/bullet/detector/unused_eager_loading.rb +5 -7
  30. data/lib/bullet/notification/base.rb +2 -2
  31. data/lib/bullet/rack.rb +1 -1
  32. data/lib/bullet/version.rb +1 -1
  33. data/lib/bullet.rb +8 -3
  34. data/spec/bullet/detector/unused_eager_loading_spec.rb +14 -2
  35. data/spec/bullet/rack_spec.rb +31 -0
  36. data/spec/bullet_spec.rb +9 -0
  37. data/spec/integration/active_record3/association_spec.rb +65 -1
  38. data/spec/integration/active_record4/association_spec.rb +56 -13
  39. data/spec/integration/active_record5/association_spec.rb +56 -13
  40. data/spec/spec_helper.rb +0 -3
  41. data/spec/support/sqlite_seed.rb +1 -0
  42. data/test.sh +1 -0
  43. data/update.sh +1 -0
  44. metadata +4 -4
@@ -29,6 +29,14 @@ module Bullet
29
29
  end
30
30
  end
31
31
  alias_method_chain :save, :bullet
32
+
33
+ def save_with_bullet!(*args, &proc)
34
+ was_new_record = new_record?
35
+ save_without_bullet!(*args, &proc).tap do |result|
36
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
37
+ end
38
+ end
39
+ alias_method_chain :save!, :bullet
32
40
  end
33
41
 
34
42
  ::ActiveRecord::Relation.class_eval do
@@ -127,7 +135,9 @@ module Bullet
127
135
  records = origin_load_target
128
136
 
129
137
  if Bullet.start?
130
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
138
+ if records.size > 1
139
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
140
+ end
131
141
  if records.first.class.name !~ /^HABTM_/
132
142
  if records.size > 1
133
143
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
@@ -143,7 +153,7 @@ module Bullet
143
153
 
144
154
  alias_method :origin_empty?, :empty?
145
155
  def empty?
146
- if Bullet.start?
156
+ if Bullet.start? && !has_cached_counter?(@reflection)
147
157
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
148
158
  end
149
159
  origin_empty?
@@ -183,7 +193,7 @@ module Bullet
183
193
  Thread.current[:bullet_collection_empty] = true
184
194
  result = origin_many_empty?
185
195
  Thread.current[:bullet_collection_empty] = nil
186
- if Bullet.start?
196
+ if Bullet.start? && !has_cached_counter?(@reflection)
187
197
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
188
198
  end
189
199
  result
@@ -1,4 +1,20 @@
1
1
  module Bullet
2
+ module SaveWithBulletSupport
3
+ def save(*args)
4
+ was_new_record = new_record?
5
+ super(*args).tap do |result|
6
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
7
+ end
8
+ end
9
+
10
+ def save!(*args)
11
+ was_new_record = new_record?
12
+ super(*args).tap do |result|
13
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
14
+ end
15
+ end
16
+ end
17
+
2
18
  module ActiveRecord
3
19
  def self.enable
4
20
  require 'active_record'
@@ -21,49 +37,33 @@ module Bullet
21
37
  end
22
38
  end
23
39
 
24
- ::ActiveRecord::Persistence.class_eval do
25
- def save_with_bullet(*args, &proc)
26
- was_new_record = new_record?
27
- save_without_bullet(*args, &proc).tap do |result|
28
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
29
- end
30
- end
31
- alias_method_chain :save, :bullet
32
- end
40
+ ::ActiveRecord::Base.prepend(SaveWithBulletSupport)
33
41
 
34
42
  ::ActiveRecord::Relation.class_eval do
35
- alias_method :origin_to_a, :to_a
43
+ alias_method :origin_records, :records
36
44
  # if select a collection of objects, then these objects have possible to cause N+1 query.
37
45
  # if select only one object, then the only one object has impossible to cause N+1 query.
38
- def to_a
39
- records = origin_to_a
46
+ def records
47
+ result = origin_records
40
48
  if Bullet.start?
41
- if records.first.class.name !~ /^HABTM_/
42
- if records.size > 1
43
- Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
44
- Bullet::Detector::CounterCache.add_possible_objects(records)
45
- elsif records.size == 1
46
- Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
47
- Bullet::Detector::CounterCache.add_impossible_object(records.first)
49
+ if result.first.class.name !~ /^HABTM_/
50
+ if result.size > 1
51
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
52
+ Bullet::Detector::CounterCache.add_possible_objects(result)
53
+ elsif result.size == 1
54
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result.first)
55
+ Bullet::Detector::CounterCache.add_impossible_object(result.first)
48
56
  end
49
57
  end
50
58
  end
51
- records
52
- end
53
- end
54
-
55
- ::ActiveRecord::Associations::Association.class_eval do
56
- alias_method :origin_initialize, :initialize
57
- def initialize(owner, reflection)
58
- origin_initialize(owner, reflection)
59
- reflection.set_owner owner
59
+ result
60
60
  end
61
61
  end
62
62
 
63
63
  ::ActiveRecord::Associations::Preloader.class_eval do
64
- alias_method :origin_preloaders_on, :preloaders_on
64
+ alias_method :origin_preloaders_for_one, :preloaders_for_one
65
65
 
66
- def preloaders_on(association, records, scope)
66
+ def preloaders_for_one(association, records, scope)
67
67
  if Bullet.start?
68
68
  records.compact!
69
69
  if records.first.class.name !~ /^HABTM_/
@@ -73,7 +73,7 @@ module Bullet
73
73
  Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
74
74
  end
75
75
  end
76
- origin_preloaders_on(association, records, scope)
76
+ origin_preloaders_for_one(association, records, scope)
77
77
  end
78
78
  end
79
79
 
@@ -135,7 +135,16 @@ module Bullet
135
135
  records = origin_load_target
136
136
 
137
137
  if Bullet.start?
138
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
138
+ if records.size > 1
139
+ if self.is_a? ::ActiveRecord::Associations::ThroughAssociation
140
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
141
+ association = self.owner.association self.through_reflection.name
142
+ association.target.each do |through_record|
143
+ Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
144
+ end
145
+ end
146
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
147
+ end
139
148
  if records.first.class.name !~ /^HABTM_/
140
149
  if records.size > 1
141
150
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
@@ -151,8 +160,8 @@ module Bullet
151
160
 
152
161
  alias_method :origin_empty?, :empty?
153
162
  def empty?
154
- if Bullet.start?
155
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
163
+ if Bullet.start? && !reflection.has_cached_counter?
164
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
156
165
  end
157
166
  origin_empty?
158
167
  end
@@ -160,7 +169,7 @@ module Bullet
160
169
  alias_method :origin_include?, :include?
161
170
  def include?(object)
162
171
  if Bullet.start?
163
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
172
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
164
173
  end
165
174
  origin_include?(object)
166
175
  end
@@ -172,9 +181,9 @@ module Bullet
172
181
  def reader(force_reload = false)
173
182
  result = origin_reader(force_reload)
174
183
  if Bullet.start?
175
- if @owner.class.name !~ /^HABTM_/ && !@inversed
176
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
177
- if Bullet::Detector::NPlusOneQuery.impossible?(@owner)
184
+ if owner.class.name !~ /^HABTM_/ && !@inversed
185
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
186
+ if Bullet::Detector::NPlusOneQuery.impossible?(owner)
178
187
  Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
179
188
  else
180
189
  Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
@@ -188,28 +197,20 @@ module Bullet
188
197
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
189
198
  alias_method :origin_many_empty?, :empty?
190
199
  def empty?
191
- Thread.current[:bullet_collection_empty] = true
192
200
  result = origin_many_empty?
193
- Thread.current[:bullet_collection_empty] = nil
194
- if Bullet.start?
195
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
201
+ if Bullet.start? && !reflection.has_cached_counter?
202
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name)
196
203
  end
197
204
  result
198
205
  end
199
- end
200
-
201
- ::ActiveRecord::Reflection::AbstractReflection.class_eval do
202
- def set_owner(owner)
203
- @owner = owner
204
- end
205
206
 
206
- alias_method :origin_has_cached_counter?, :has_cached_counter?
207
- def has_cached_counter?
208
- result = origin_has_cached_counter?
209
- if Bullet.start? && !result && !Thread.current[:bullet_collection_empty]
210
- Bullet::Detector::CounterCache.add_counter_cache(@owner, @name)
207
+ alias_method :origin_count_records, :count_records
208
+ def count_records
209
+ result = reflection.has_cached_counter?
210
+ if Bullet.start? && !result && !self.is_a?(::ActiveRecord::Associations::ThroughAssociation)
211
+ Bullet::Detector::CounterCache.add_counter_cache(owner, reflection.name)
211
212
  end
212
- result
213
+ origin_count_records
213
214
  end
214
215
  end
215
216
  end
@@ -27,27 +27,25 @@ module Bullet
27
27
  Bullet.debug("Detector::UnusedEagerLoading#add_eager_loadings", "objects: #{objects.map(&:bullet_key).join(', ')}, associations: #{associations}")
28
28
  bullet_keys = objects.map(&:bullet_key)
29
29
 
30
- to_add = nil
31
- to_merge, to_delete = [], []
30
+ to_add, to_merge, to_delete = [], [], []
32
31
  eager_loadings.each do |k, v|
33
32
  key_objects_overlap = k & bullet_keys
34
33
 
35
34
  next if key_objects_overlap.empty?
36
35
 
36
+ bullet_keys = bullet_keys - k
37
37
  if key_objects_overlap == k
38
- to_add = [k, associations]
39
- break
38
+ to_add << [k, associations]
40
39
  else
41
40
  to_merge << [key_objects_overlap, ( eager_loadings[k].dup << associations )]
42
41
 
43
- keys_without_objects = k - bullet_keys
42
+ keys_without_objects = k - key_objects_overlap
44
43
  to_merge << [keys_without_objects, eager_loadings[k]]
45
44
  to_delete << k
46
- bullet_keys = bullet_keys - k
47
45
  end
48
46
  end
49
47
 
50
- eager_loadings.add(*to_add) if to_add
48
+ to_add.each { |k, val| eager_loadings.add k, val }
51
49
  to_merge.each { |k, val| eager_loadings.merge k, val }
52
50
  to_delete.each { |k| eager_loadings.delete k }
53
51
 
@@ -57,11 +57,11 @@ module Bullet
57
57
  end
58
58
 
59
59
  def eql?(other)
60
- klazz_associations_str == other.klazz_associations_str
60
+ self.class == other.class && klazz_associations_str == other.klazz_associations_str
61
61
  end
62
62
 
63
63
  def hash
64
- klazz_associations_str.hash
64
+ [self.class, klazz_associations_str].hash
65
65
  end
66
66
 
67
67
  protected
data/lib/bullet/rack.rb CHANGED
@@ -67,7 +67,7 @@ module Bullet
67
67
  end
68
68
 
69
69
  def response_body(response)
70
- if rails?
70
+ if response.respond_to?(:body)
71
71
  Array === response.body ? response.body.first : response.body
72
72
  else
73
73
  response.first
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Bullet
3
- VERSION = "5.0.0"
3
+ VERSION = "5.2.0"
4
4
  end
data/lib/bullet.rb CHANGED
@@ -82,8 +82,8 @@ module Bullet
82
82
 
83
83
  def add_whitelist(options)
84
84
  reset_whitelist
85
- @whitelist[options[:type]][options[:class_name].classify] ||= []
86
- @whitelist[options[:type]][options[:class_name].classify] << options[:association].to_sym
85
+ @whitelist[options[:type]][options[:class_name]] ||= []
86
+ @whitelist[options[:type]][options[:class_name]] << options[:association].to_sym
87
87
  end
88
88
 
89
89
  def get_whitelist_associations(type, class_name)
@@ -190,17 +190,22 @@ module Bullet
190
190
  end
191
191
 
192
192
  def profile
193
+ return_value = nil
193
194
  if Bullet.enable?
194
195
  begin
195
196
  Bullet.start_request
196
197
 
197
- yield
198
+ return_value = yield
198
199
 
199
200
  Bullet.perform_out_of_channel_notifications if Bullet.notification?
200
201
  ensure
201
202
  Bullet.end_request
202
203
  end
204
+ else
205
+ return_value = yield
203
206
  end
207
+
208
+ return_value
204
209
  end
205
210
 
206
211
  private
@@ -5,7 +5,8 @@ module Bullet
5
5
  describe UnusedEagerLoading do
6
6
  before(:all) do
7
7
  @post = Post.first
8
- @post2 = Post.last
8
+ @post2 = Post.all[1]
9
+ @post3 = Post.last
9
10
  end
10
11
 
11
12
  context ".call_associations" do
@@ -72,7 +73,18 @@ module Bullet
72
73
  UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
73
74
  expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
74
75
  expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association2)
75
- expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key, @post2.bullet_key], :association2)
76
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post2.bullet_key], :association2)
77
+ end
78
+
79
+ it "should vmerge objects recursively, associations pair for existing eager_loadings" do
80
+ UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
81
+ UnusedEagerLoading.add_eager_loadings([@post, @post3], :association1)
82
+ UnusedEagerLoading.add_eager_loadings([@post, @post3], :association2)
83
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
84
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association2)
85
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post2.bullet_key], :association1)
86
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post3.bullet_key], :association1)
87
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post3.bullet_key], :association2)
76
88
  end
77
89
 
78
90
  it "should delete objects, associations pair for existing eager_loadings" do
@@ -93,5 +93,36 @@ module Bullet
93
93
  end
94
94
  end
95
95
  end
96
+
97
+ describe "#response_body" do
98
+ let(:response) { double }
99
+ let(:body_string) { "<html><body>My Body</body></html>" }
100
+
101
+ context "when `response` responds to `body`" do
102
+ before { allow(response).to receive(:body).and_return(body) }
103
+
104
+ context "when `body` returns an Array" do
105
+ let(:body) { [body_string, 'random string'] }
106
+ it "should return the plain body string" do
107
+ expect(middleware.response_body(response)).to eq body_string
108
+ end
109
+ end
110
+
111
+ context "when `body` does not return an Array" do
112
+ let(:body) { body_string }
113
+ it "should return the plain body string" do
114
+ expect(middleware.response_body(response)).to eq body_string
115
+ end
116
+ end
117
+ end
118
+
119
+ context "when `response` does not respond to `body`" do
120
+ before { allow(response).to receive(:first).and_return(body_string) }
121
+
122
+ it "should return the plain body string" do
123
+ expect(middleware.response_body(response)).to eq body_string
124
+ end
125
+ end
126
+ end
96
127
  end
97
128
  end
data/spec/bullet_spec.rb CHANGED
@@ -85,4 +85,13 @@ describe Bullet, focused: true do
85
85
  end
86
86
  end
87
87
  end
88
+
89
+ describe '#add_whitelist' do
90
+ context "for 'special' class names" do
91
+ it 'is added to the whitelist successfully' do
92
+ Bullet.add_whitelist(:type => :n_plus_one_query, :class_name => 'Klass', :association => :department)
93
+ expect(Bullet.get_whitelist_associations(:n_plus_one_query, 'Klass')).to include :department
94
+ end
95
+ end
96
+ end
88
97
  end
@@ -72,6 +72,16 @@ if !mongoid? && active_record3?
72
72
 
73
73
  expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
74
74
  end
75
+
76
+ it "should not detect unused preload person => pets with empty?" do
77
+ Person.all.each do |person|
78
+ person.pets.empty?
79
+ end
80
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
81
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
82
+
83
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
84
+ end
75
85
  end
76
86
 
77
87
  context "category => posts => comments" do
@@ -204,7 +214,7 @@ if !mongoid? && active_record3?
204
214
  context "post => comment" do
205
215
  it "should detect unused preload with post => comments" do
206
216
  Post.includes(:comments).each do |post|
207
- post.comments.first.name
217
+ post.comments.first.name if post.comments.first
208
218
  end
209
219
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
210
220
  expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :comments)
@@ -443,6 +453,16 @@ if !mongoid? && active_record3?
443
453
 
444
454
  expect(Bullet::Detector::Association).to be_completely_preloading_associations
445
455
  end
456
+
457
+ it "should detect non preload student => teachers with empty?" do
458
+ Student.all.each do |student|
459
+ student.teachers.empty?
460
+ end
461
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
462
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
463
+
464
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Student, :teachers)
465
+ end
446
466
  end
447
467
  end
448
468
 
@@ -537,6 +557,50 @@ if !mongoid? && active_record3?
537
557
  end
538
558
  end
539
559
 
560
+ describe Bullet::Detector::Association, "query immediately after creation" do
561
+ context "with save" do
562
+ context "document => children" do
563
+ it 'should not detect non preload associations' do
564
+ document1 = Document.new
565
+ document1.children.build
566
+ document1.save
567
+
568
+ document2 = Document.new(parent: document1)
569
+ document2.save
570
+ document2.parent
571
+
572
+ document1.children.each.first
573
+
574
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
575
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
576
+
577
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
578
+ end
579
+ end
580
+ end
581
+
582
+ context "with save!" do
583
+ context "document => children" do
584
+ it 'should not detect non preload associations' do
585
+ document1 = Document.new
586
+ document1.children.build
587
+ document1.save!
588
+
589
+ document2 = Document.new(parent: document1)
590
+ document2.save!
591
+ document2.parent
592
+
593
+ document1.children.each.first
594
+
595
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
596
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
597
+
598
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
599
+ end
600
+ end
601
+ end
602
+ end
603
+
540
604
  describe Bullet::Detector::Association, "STI" do
541
605
  context "page => author" do
542
606
  it "should detect non preload associations" do
@@ -72,6 +72,16 @@ if !mongoid? && active_record4?
72
72
 
73
73
  expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
74
74
  end
75
+
76
+ it "should not detect unused preload person => pets with empty?" do
77
+ Person.all.each do |person|
78
+ person.pets.empty?
79
+ end
80
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
81
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
82
+
83
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
84
+ end
75
85
  end
76
86
 
77
87
  context "category => posts => comments" do
@@ -204,7 +214,7 @@ if !mongoid? && active_record4?
204
214
  context "post => comment" do
205
215
  it "should detect unused preload with post => comments" do
206
216
  Post.includes(:comments).each do |post|
207
- post.comments.first.name
217
+ post.comments.first.name if post.comments.first
208
218
  end
209
219
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
210
220
  expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :comments)
@@ -455,6 +465,16 @@ if !mongoid? && active_record4?
455
465
 
456
466
  expect(Bullet::Detector::Association).to be_completely_preloading_associations
457
467
  end
468
+
469
+ it "should detect non preload student => teachers with empty?" do
470
+ Student.all.each do |student|
471
+ student.teachers.empty?
472
+ end
473
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
474
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
475
+
476
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Student, :teachers)
477
+ end
458
478
  end
459
479
  end
460
480
 
@@ -561,22 +581,45 @@ if !mongoid? && active_record4?
561
581
  end
562
582
 
563
583
  describe Bullet::Detector::Association, "query immediately after creation" do
564
- context "document => children" do
565
- it 'should not detect non preload associations' do
566
- document1 = Document.new
567
- document1.children.build
568
- document1.save
584
+ context "with save" do
585
+ context "document => children" do
586
+ it 'should not detect non preload associations' do
587
+ document1 = Document.new
588
+ document1.children.build
589
+ document1.save
569
590
 
570
- document2 = Document.new(parent: document1)
571
- document2.save
572
- document2.parent
591
+ document2 = Document.new(parent: document1)
592
+ document2.save
593
+ document2.parent
573
594
 
574
- document1.children.each.first
595
+ document1.children.each.first
575
596
 
576
- Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
577
- expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
597
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
598
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
578
599
 
579
- expect(Bullet::Detector::Association).to be_completely_preloading_associations
600
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
601
+ end
602
+ end
603
+ end
604
+
605
+ context "with save!" do
606
+ context "document => children" do
607
+ it 'should not detect non preload associations' do
608
+ document1 = Document.new
609
+ document1.children.build
610
+ document1.save!
611
+
612
+ document2 = Document.new(parent: document1)
613
+ document2.save!
614
+ document2.parent
615
+
616
+ document1.children.each.first
617
+
618
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
619
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
620
+
621
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
622
+ end
580
623
  end
581
624
  end
582
625
  end