bullet 4.14.10 → 5.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 262911eb5bb5cc6577489084cca4c06042ec466b
4
- data.tar.gz: 6aa0f9e1403c8f36cac9375b451880a82c9561cd
3
+ metadata.gz: d5439116cdedcd96dfad6dfd315eaf47ee815153
4
+ data.tar.gz: 9542679b93fa670fbf8b014fb0cbd3adb13a30d8
5
5
  SHA512:
6
- metadata.gz: 99c812cc4085c2e9763ba05564f98b4b3ab9027820932eb70d09060fbfb69071d38d8d844b67d29dc167ad04983e8133fa5727b426122d9a4e0f3b9c55e9bd3b
7
- data.tar.gz: d1316bb72c9228fb4b7746795d528506eb472d1bd906424c17bbb5a3adcdd995e75bcdec59b8a93959d80e9ef88e0bfb692092db505c95a50fcd32735f4dda8e
6
+ metadata.gz: 4704ead627526344ab065d5d0a9bd2f3516165f664d9ab97aca3dd576c55ecc75450636daceebe21d100562be45c5e9352296ea0cd5856b0a4205be2120751cb
7
+ data.tar.gz: 6b3d52be604e5188920592e6b3952d2a683364631739c097b619b151f9131b911454452eae824e13493a4866ff767eb9ba61da3a98097aa3042e498faf74bdd6
@@ -4,7 +4,9 @@ rvm:
4
4
  - 2.0
5
5
  - 2.1
6
6
  - 2.2
7
+ - 2.2.3
7
8
  gemfile:
9
+ - Gemfile.rails-5.0
8
10
  - Gemfile.rails-4.2
9
11
  - Gemfile.rails-4.1
10
12
  - Gemfile.rails-4.0
@@ -26,6 +28,12 @@ services:
26
28
  - mongodb
27
29
  matrix:
28
30
  exclude:
31
+ - rvm: 2.0
32
+ gemfile: Gemfile.rails-5.0
33
+ - rvm: 2.1
34
+ gemfile: Gemfile.rails-5.0
35
+ - rvm: 2.2
36
+ gemfile: Gemfile.rails-5.0
29
37
  - rvm: 2.2
30
38
  gemfile: Gemfile.rails-3.0
31
39
  - rvm: 2.2
@@ -46,3 +54,23 @@ matrix:
46
54
  gemfile: Gemfile.mongoid-2.5
47
55
  - rvm: 2.2
48
56
  gemfile: Gemfile.mongoid-2.4
57
+ - rvm: 2.2.3
58
+ gemfile: Gemfile.rails-3.0
59
+ - rvm: 2.2.3
60
+ gemfile: Gemfile.rails-3.1
61
+ - rvm: 2.2.3
62
+ gemfile: Gemfile.rails-3.2
63
+ - rvm: 2.2.3
64
+ gemfile: Gemfile.mongoid-3.1
65
+ - rvm: 2.2.3
66
+ gemfile: Gemfile.mongoid-3.0
67
+ - rvm: 2.2.3
68
+ gemfile: Gemfile.mongoid-2.8
69
+ - rvm: 2.2.3
70
+ gemfile: Gemfile.mongoid-2.7
71
+ - rvm: 2.2.3
72
+ gemfile: Gemfile.mongoid-2.6
73
+ - rvm: 2.2.3
74
+ gemfile: Gemfile.mongoid-2.5
75
+ - rvm: 2.2.3
76
+ gemfile: Gemfile.mongoid-2.4
@@ -1,5 +1,9 @@
1
1
  # Next Release
2
2
 
3
+ ## 5.0.0 (01/06/2015)
4
+
5
+ * Support Rails 5.0.0.beta1
6
+
3
7
  ## 4.14.10
4
8
 
5
9
  * Fix `has_many :through` infinite loop issue
@@ -0,0 +1,17 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'rails', '5.0.0.beta1'
6
+ gem 'sqlite3'
7
+ gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
+ gem 'activerecord-import'
9
+
10
+ gem "rspec"
11
+
12
+ gem 'coveralls', require: false
13
+
14
+ platforms :rbx do
15
+ gem 'rubysl', '~> 2.0'
16
+ gem 'rubinius-developer_tools'
17
+ end
data/README.md CHANGED
@@ -62,6 +62,7 @@ config.after_initialize do
62
62
  Bullet.rollbar = true
63
63
  Bullet.add_footer = true
64
64
  Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
65
+ Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware' ]
65
66
  Bullet.slack = { webhook_url: 'http://some.slack.url', foo: 'bar' }
66
67
  end
67
68
  ```
@@ -83,6 +84,7 @@ The code above will enable all seven of the Bullet notification systems:
83
84
  * `Bullet.raise`: raise errors, useful for making your specs fail unless they have optimized queries
84
85
  * `Bullet.add_footer`: adds the details in the bottom left corner of the page
85
86
  * `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
87
+ * `Bullet.stacktrace_excludes`: ignore paths with any of these substrings in the stack trace, even if they are not in your main app.
86
88
  * `Bullet.slack`: add notifications to slack
87
89
 
88
90
  Bullet also allows you to disable any of its detectors.
@@ -28,7 +28,7 @@ module Bullet
28
28
  end
29
29
 
30
30
  class << self
31
- attr_writer :enable, :n_plus_one_query_enable, :unused_eager_loading_enable, :counter_cache_enable, :stacktrace_includes
31
+ attr_writer :enable, :n_plus_one_query_enable, :unused_eager_loading_enable, :counter_cache_enable, :stacktrace_includes, :stacktrace_excludes
32
32
  attr_reader :notification_collector, :whitelist
33
33
  attr_accessor :add_footer, :orm_pathches_applied
34
34
 
@@ -76,6 +76,10 @@ module Bullet
76
76
  @stacktrace_includes || []
77
77
  end
78
78
 
79
+ def stacktrace_excludes
80
+ @stacktrace_excludes || []
81
+ end
82
+
79
83
  def add_whitelist(options)
80
84
  reset_whitelist
81
85
  @whitelist[options[:type]][options[:class_name].classify] ||= []
@@ -0,0 +1,217 @@
1
+ module Bullet
2
+ module ActiveRecord
3
+ def self.enable
4
+ require 'active_record'
5
+ ::ActiveRecord::Base.class_eval do
6
+ class <<self
7
+ alias_method :origin_find, :find
8
+ def find(*args)
9
+ result = origin_find(*args)
10
+ if Bullet.start?
11
+ if result.is_a? Array
12
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
13
+ Bullet::Detector::CounterCache.add_possible_objects(result)
14
+ elsif result.is_a? ::ActiveRecord::Base
15
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
16
+ Bullet::Detector::CounterCache.add_impossible_object(result)
17
+ end
18
+ end
19
+ result
20
+ end
21
+ end
22
+ end
23
+
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
33
+
34
+ ::ActiveRecord::Relation.class_eval do
35
+ alias_method :origin_to_a, :to_a
36
+ # if select a collection of objects, then these objects have possible to cause N+1 query.
37
+ # 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
40
+ 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)
48
+ end
49
+ end
50
+ 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
60
+ end
61
+ end
62
+
63
+ ::ActiveRecord::Associations::Preloader.class_eval do
64
+ alias_method :origin_preloaders_on, :preloaders_on
65
+
66
+ def preloaders_on(association, records, scope)
67
+ if Bullet.start?
68
+ records.compact!
69
+ if records.first.class.name !~ /^HABTM_/
70
+ records.each do |record|
71
+ Bullet::Detector::Association.add_object_associations(record, association)
72
+ end
73
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, association)
74
+ end
75
+ end
76
+ origin_preloaders_on(association, records, scope)
77
+ end
78
+ end
79
+
80
+ ::ActiveRecord::FinderMethods.class_eval do
81
+ # add includes in scope
82
+ alias_method :origin_find_with_associations, :find_with_associations
83
+ def find_with_associations
84
+ return origin_find_with_associations { |r| yield r } if block_given?
85
+ records = origin_find_with_associations
86
+ if Bullet.start?
87
+ associations = (eager_load_values + includes_values).uniq
88
+ records.each do |record|
89
+ Bullet::Detector::Association.add_object_associations(record, associations)
90
+ end
91
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(records, associations)
92
+ end
93
+ records
94
+ end
95
+ end
96
+
97
+ ::ActiveRecord::Associations::JoinDependency.class_eval do
98
+ alias_method :origin_instantiate, :instantiate
99
+ alias_method :origin_construct_model, :construct_model
100
+
101
+ def instantiate(result_set, aliases)
102
+ @bullet_eager_loadings = {}
103
+ records = origin_instantiate(result_set, aliases)
104
+
105
+ if Bullet.start?
106
+ @bullet_eager_loadings.each do |klazz, eager_loadings_hash|
107
+ objects = eager_loadings_hash.keys
108
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(objects, eager_loadings_hash[objects.first].to_a)
109
+ end
110
+ end
111
+ records
112
+ end
113
+
114
+ # call join associations
115
+ def construct_model(record, node, row, model_cache, id, aliases)
116
+ result = origin_construct_model(record, node, row, model_cache, id, aliases)
117
+
118
+ if Bullet.start?
119
+ associations = node.reflection.name
120
+ Bullet::Detector::Association.add_object_associations(record, associations)
121
+ Bullet::Detector::NPlusOneQuery.call_association(record, associations)
122
+ @bullet_eager_loadings[record.class] ||= {}
123
+ @bullet_eager_loadings[record.class][record] ||= Set.new
124
+ @bullet_eager_loadings[record.class][record] << associations
125
+ end
126
+
127
+ result
128
+ end
129
+ end
130
+
131
+ ::ActiveRecord::Associations::CollectionAssociation.class_eval do
132
+ # call one to many associations
133
+ alias_method :origin_load_target, :load_target
134
+ def load_target
135
+ records = origin_load_target
136
+
137
+ if Bullet.start?
138
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
139
+ if records.first.class.name !~ /^HABTM_/
140
+ if records.size > 1
141
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
142
+ Bullet::Detector::CounterCache.add_possible_objects(records)
143
+ elsif records.size == 1
144
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
145
+ Bullet::Detector::CounterCache.add_impossible_object(records.first)
146
+ end
147
+ end
148
+ end
149
+ records
150
+ end
151
+
152
+ alias_method :origin_empty?, :empty?
153
+ def empty?
154
+ if Bullet.start?
155
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
156
+ end
157
+ origin_empty?
158
+ end
159
+
160
+ alias_method :origin_include?, :include?
161
+ def include?(object)
162
+ if Bullet.start?
163
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
164
+ end
165
+ origin_include?(object)
166
+ end
167
+ end
168
+
169
+ ::ActiveRecord::Associations::SingularAssociation.class_eval do
170
+ # call has_one and belongs_to associations
171
+ alias_method :origin_reader, :reader
172
+ def reader(force_reload = false)
173
+ result = origin_reader(force_reload)
174
+ 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)
178
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
179
+ else
180
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result) if result
181
+ end
182
+ end
183
+ end
184
+ result
185
+ end
186
+ end
187
+
188
+ ::ActiveRecord::Associations::HasManyAssociation.class_eval do
189
+ alias_method :origin_many_empty?, :empty?
190
+ def empty?
191
+ Thread.current[:bullet_collection_empty] = true
192
+ result = origin_many_empty?
193
+ Thread.current[:bullet_collection_empty] = nil
194
+ if Bullet.start?
195
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
196
+ end
197
+ result
198
+ end
199
+ end
200
+
201
+ ::ActiveRecord::Reflection::AbstractReflection.class_eval do
202
+ def set_owner(owner)
203
+ @owner = owner
204
+ end
205
+
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)
211
+ end
212
+ result
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -24,6 +24,8 @@ module Bullet
24
24
  'active_record41'
25
25
  elsif active_record42?
26
26
  'active_record42'
27
+ elsif active_record50?
28
+ 'active_record5'
27
29
  end
28
30
  end
29
31
  end
@@ -50,6 +52,10 @@ module Bullet
50
52
  active_record? && ::ActiveRecord::VERSION::MAJOR == 4
51
53
  end
52
54
 
55
+ def active_record5?
56
+ active_record? && ::ActiveRecord::VERSION::MAJOR == 5
57
+ end
58
+
53
59
  def active_record30?
54
60
  active_record3? && ::ActiveRecord::VERSION::MINOR == 0
55
61
  end
@@ -74,6 +80,10 @@ module Bullet
74
80
  active_record4? && ::ActiveRecord::VERSION::MINOR == 2
75
81
  end
76
82
 
83
+ def active_record50?
84
+ active_record5? && ::ActiveRecord::VERSION::MINOR == 0
85
+ end
86
+
77
87
  def mongoid2x?
78
88
  mongoid? && ::Mongoid::VERSION =~ /\A2\.[4-8]/
79
89
  end
@@ -15,7 +15,7 @@ module Bullet
15
15
  add_call_object_associations(object, associations)
16
16
 
17
17
  Bullet.debug("Detector::NPlusOneQuery#call_association", "object: #{object.bullet_key}, associations: #{associations}")
18
- if conditions_met?(object, associations)
18
+ if !excluded_stacktrace_path? && conditions_met?(object, associations)
19
19
  Bullet.debug("detect n + 1 query", "object: #{object.bullet_key}, associations: #{associations}")
20
20
  create_notification caller_in_project, object.class.to_s, associations
21
21
  end
@@ -96,6 +96,12 @@ module Bullet
96
96
  Bullet.stacktrace_includes.any? { |include| c.include?(include) }
97
97
  end
98
98
  end
99
+
100
+ def excluded_stacktrace_path?
101
+ Bullet.stacktrace_excludes.any? do |excluded_path|
102
+ caller_in_project.any? { |c| c.include?(excluded_path) }
103
+ end
104
+ end
99
105
  end
100
106
  end
101
107
  end
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Bullet
3
- VERSION = "4.14.10"
3
+ VERSION = "5.0.0"
4
4
  end
@@ -85,6 +85,21 @@ module Bullet
85
85
  expect(NPlusOneQuery).not_to receive(:create_notification).with("Post", :association)
86
86
  NPlusOneQuery.call_association(@post, :association)
87
87
  end
88
+
89
+ context "stacktrace_excludes" do
90
+ before { Bullet.stacktrace_excludes = [ 'def' ] }
91
+ after { Bullet.stacktrace_excludes = nil }
92
+
93
+ it "should not create notification when stacktrace contains paths that are in the exclude list" do
94
+ in_project = File.join(Dir.pwd, 'abc', 'abc.rb')
95
+ included_path = '/ghi/ghi.rb'
96
+ excluded_path = '/def/def.rb'
97
+
98
+ expect(NPlusOneQuery).to receive(:caller).and_return([in_project, included_path, excluded_path])
99
+ expect(NPlusOneQuery).to_not receive(:create_notification)
100
+ NPlusOneQuery.call_association(@post, :association)
101
+ end
102
+ end
88
103
  end
89
104
 
90
105
  context ".caller_in_project" do
@@ -0,0 +1,715 @@
1
+ require 'spec_helper'
2
+
3
+ if !mongoid? && active_record5?
4
+ describe Bullet::Detector::Association, 'has_many' do
5
+ context "post => comments" do
6
+ it "should detect non preload post => comments" do
7
+ Post.all.each do |post|
8
+ post.comments.map(&:name)
9
+ end
10
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
11
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
12
+
13
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
14
+ end
15
+
16
+ it "should detect preload with post => comments" do
17
+ Post.includes(:comments).each do |post|
18
+ post.comments.map(&:name)
19
+ end
20
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
21
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
22
+
23
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
24
+ end
25
+
26
+ it "should detect unused preload post => comments" do
27
+ Post.includes(:comments).map(&:name)
28
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
29
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Post, :comments)
30
+
31
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
32
+ end
33
+
34
+ it "should not detect unused preload post => comments" do
35
+ Post.all.map(&:name)
36
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
37
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
38
+
39
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
40
+ end
41
+
42
+ it "should detect non preload comment => post with inverse_of" do
43
+ Post.includes(:comments).each do |post|
44
+ post.comments.each do |comment|
45
+ comment.name
46
+ comment.post.name
47
+ end
48
+ end
49
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
50
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
51
+
52
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
53
+ end
54
+
55
+ it "should detect non preload post => comments with empty?" do
56
+ Post.all.each do |post|
57
+ post.comments.empty?
58
+ end
59
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
60
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
61
+
62
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
63
+ end
64
+
65
+ it "should detect non preload post => comments with include?" do
66
+ comment = Comment.last
67
+ Post.all.each do |post|
68
+ post.comments.include?(comment)
69
+ end
70
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
71
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
72
+
73
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
74
+ end
75
+ end
76
+
77
+ context "category => posts => comments" do
78
+ it "should detect non preload category => posts => comments" do
79
+ Category.all.each do |category|
80
+ category.posts.each do |post|
81
+ post.comments.map(&:name)
82
+ end
83
+ end
84
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
85
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
86
+
87
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Category, :posts)
88
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
89
+ end
90
+
91
+ it "should detect preload category => posts, but no post => comments" do
92
+ Category.includes(:posts).each do |category|
93
+ category.posts.each do |post|
94
+ post.comments.map(&:name)
95
+ end
96
+ end
97
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
98
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
99
+
100
+ expect(Bullet::Detector::Association).not_to be_detecting_unpreloaded_association_for(Category, :posts)
101
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
102
+ end
103
+
104
+ it "should detect preload with category => posts => comments" do
105
+ Category.includes({:posts => :comments}).each do |category|
106
+ category.posts.each do |post|
107
+ post.comments.map(&:name)
108
+ end
109
+ end
110
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
111
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
112
+
113
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
114
+ end
115
+
116
+ it "should detect preload with category => posts => comments with posts.id > 0" do
117
+ Category.includes({:posts => :comments}).where('posts.id > 0').references(:posts).each do |category|
118
+ category.posts.each do |post|
119
+ post.comments.map(&:name)
120
+ end
121
+ end
122
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
123
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
124
+
125
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
126
+ end
127
+
128
+ it "should detect unused preload with category => posts => comments" do
129
+ Category.includes({:posts => :comments}).map(&:name)
130
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
131
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Post, :comments)
132
+
133
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
134
+ end
135
+
136
+ it "should detect unused preload with post => commnets, no category => posts" do
137
+ Category.includes({:posts => :comments}).each do |category|
138
+ category.posts.map(&:name)
139
+ end
140
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
141
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Post, :comments)
142
+
143
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
144
+ end
145
+ end
146
+
147
+ context "category => posts, category => entries" do
148
+ it "should detect non preload with category => [posts, entries]" do
149
+ Category.all.each do |category|
150
+ category.posts.map(&:name)
151
+ category.entries.map(&:name)
152
+ end
153
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
154
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
155
+
156
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Category, :posts)
157
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Category, :entries)
158
+ end
159
+
160
+ it "should detect preload with category => posts, but not with category => entries" do
161
+ Category.includes(:posts).each do |category|
162
+ category.posts.map(&:name)
163
+ category.entries.map(&:name)
164
+ end
165
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
166
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
167
+
168
+ expect(Bullet::Detector::Association).not_to be_detecting_unpreloaded_association_for(Category, :posts)
169
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Category, :entries)
170
+ end
171
+
172
+ it "should detect preload with category => [posts, entries]" do
173
+ Category.includes([:posts, :entries]).each do |category|
174
+ category.posts.map(&:name)
175
+ category.entries.map(&:name)
176
+ end
177
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
178
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
179
+
180
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
181
+ end
182
+
183
+ it "should detect unused preload with category => [posts, entries]" do
184
+ Category.includes([:posts, :entries]).map(&:name)
185
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
186
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Category, :posts)
187
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Category, :entries)
188
+
189
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
190
+ end
191
+
192
+ it "should detect unused preload with category => entries, but not with category => posts" do
193
+ Category.includes([:posts, :entries]).each do |category|
194
+ category.posts.map(&:name)
195
+ end
196
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
197
+ expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Category, :posts)
198
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Category, :entries)
199
+
200
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
201
+ end
202
+ end
203
+
204
+ context "post => comment" do
205
+ it "should detect unused preload with post => comments" do
206
+ Post.includes(:comments).each do |post|
207
+ post.comments.first.name
208
+ end
209
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
210
+ expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :comments)
211
+
212
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
213
+ end
214
+
215
+ it "should detect preload with post => commnets" do
216
+ Post.first.comments.map(&:name)
217
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
218
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
219
+
220
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
221
+ end
222
+
223
+ it "should not detect unused preload with category => posts" do
224
+ category = Category.first
225
+ category.draft_post.destroy!
226
+ post = category.draft_post
227
+ post.update_attributes!(link: true)
228
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
229
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
230
+
231
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
232
+
233
+ Support::SqliteSeed.setup_db
234
+ Support::SqliteSeed.seed_db
235
+ end
236
+ end
237
+
238
+ context "category => posts => writer" do
239
+ it "should not detect unused preload associations" do
240
+ category = Category.includes({:posts => :writer}).order("id DESC").find_by_name('first')
241
+ category.posts.map do |post|
242
+ post.name
243
+ post.writer.name
244
+ end
245
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
246
+ expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Category, :posts)
247
+ expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :writer)
248
+ end
249
+ end
250
+
251
+ context "scope for_category_name" do
252
+ it "should detect preload with post => category" do
253
+ Post.in_category_name('first').references(:categories).each do |post|
254
+ post.category.name
255
+ end
256
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
257
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
258
+
259
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
260
+ end
261
+
262
+ it "should not be unused preload post => category" do
263
+ Post.in_category_name('first').references(:categories).map(&:name)
264
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
265
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
266
+
267
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
268
+ end
269
+ end
270
+
271
+ context "scope preload_comments" do
272
+ it "should detect preload post => comments with scope" do
273
+ Post.preload_comments.each do |post|
274
+ post.comments.map(&:name)
275
+ end
276
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
277
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
278
+
279
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
280
+ end
281
+
282
+ it "should detect unused preload with scope" do
283
+ Post.preload_comments.map(&:name)
284
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
285
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Post, :comments)
286
+
287
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
288
+ end
289
+ end
290
+ end
291
+
292
+ describe Bullet::Detector::Association, 'belongs_to' do
293
+ context "comment => post" do
294
+ it "should detect non preload with comment => post" do
295
+ Comment.all.each do |comment|
296
+ comment.post.name
297
+ end
298
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
299
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
300
+
301
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Comment, :post)
302
+ end
303
+
304
+ it "should detect preload with one comment => post" do
305
+ Comment.first.post.name
306
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
307
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
308
+
309
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
310
+ end
311
+
312
+ it "should dtect preload with comment => post" do
313
+ Comment.includes(:post).each do |comment|
314
+ comment.post.name
315
+ end
316
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
317
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
318
+
319
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
320
+ end
321
+
322
+ it "should not detect preload with comment => post" do
323
+ Comment.all.map(&:name)
324
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
325
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
326
+
327
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
328
+ end
329
+
330
+ it "should detect unused preload with comment => post" do
331
+ Comment.includes(:post).map(&:name)
332
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
333
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Comment, :post)
334
+
335
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
336
+ end
337
+ end
338
+
339
+ context "comment => post => category" do
340
+ it "should detect non preload association with comment => post" do
341
+ Comment.all.each do |comment|
342
+ comment.post.category.name
343
+ end
344
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
345
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
346
+
347
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Comment, :post)
348
+ end
349
+
350
+ it "should not detect non preload association with only one comment" do
351
+ Comment.first.post.category.name
352
+
353
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
354
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
355
+
356
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
357
+ end
358
+
359
+ it "should detect non preload association with post => category" do
360
+ Comment.includes(:post).each do |comment|
361
+ comment.post.category.name
362
+ end
363
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
364
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
365
+
366
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :category)
367
+ end
368
+
369
+ it "should not detect unpreload association" do
370
+ Comment.includes(:post => :category).each do |comment|
371
+ comment.post.category.name
372
+ end
373
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
374
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
375
+
376
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
377
+ end
378
+ end
379
+
380
+ context "comment => author, post => writer" do
381
+ it "should detect non preloaded writer" do
382
+ Comment.includes([:author, :post]).where(["base_users.id = ?", BaseUser.first]).references(:base_users).each do |comment|
383
+ comment.post.writer.name
384
+ end
385
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
386
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
387
+
388
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :writer)
389
+ end
390
+
391
+ it "should detect unused preload with comment => author" do
392
+ Comment.includes([:author, {:post => :writer}]).where(["base_users.id = ?", BaseUser.first]).references(:base_users).each do |comment|
393
+ comment.post.writer.name
394
+ end
395
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
396
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
397
+
398
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
399
+ end
400
+
401
+ it "should detect non preloading with writer => newspaper" do
402
+ Comment.includes(:post => :writer).where("posts.name like '%first%'").references(:posts).each do |comment|
403
+ comment.post.writer.newspaper.name
404
+ end
405
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
406
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
407
+
408
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Writer, :newspaper)
409
+ end
410
+
411
+ it "should not raise a stack error from posts to category" do
412
+ expect {
413
+ Comment.includes({:post => :category}).each do |com|
414
+ com.post.category
415
+ end
416
+ }.not_to raise_error()
417
+ end
418
+ end
419
+ end
420
+
421
+ describe Bullet::Detector::Association, 'has_and_belongs_to_many' do
422
+ context "students <=> teachers" do
423
+ it "should detect non preload associations" do
424
+ Student.all.each do |student|
425
+ student.teachers.map(&:name)
426
+ end
427
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
428
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
429
+
430
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Student, :teachers)
431
+ end
432
+
433
+ it "should detect preload associations" do
434
+ Student.includes(:teachers).each do |student|
435
+ student.teachers.map(&:name)
436
+ end
437
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
438
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
439
+
440
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
441
+ end
442
+
443
+ it "should detect unused preload associations" do
444
+ Student.includes(:teachers).map(&:name)
445
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
446
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Student, :teachers)
447
+
448
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
449
+ end
450
+
451
+ it "should detect no unused preload associations" do
452
+ Student.all.map(&:name)
453
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
454
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
455
+
456
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
457
+ end
458
+ end
459
+ end
460
+
461
+ describe Bullet::Detector::Association, 'has_many :through' do
462
+ context "firm => clients" do
463
+ it "should detect non preload associations" do
464
+ Firm.all.each do |firm|
465
+ firm.clients.map(&:name)
466
+ end
467
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
468
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
469
+
470
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Firm, :clients)
471
+ end
472
+
473
+ it "should detect preload associations" do
474
+ Firm.includes(:clients).each do |firm|
475
+ firm.clients.map(&:name)
476
+ end
477
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
478
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
479
+
480
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
481
+ end
482
+
483
+ it "should not detect preload associations" do
484
+ Firm.all.map(&:name)
485
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
486
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
487
+
488
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
489
+ end
490
+
491
+ it "should detect unused preload associations" do
492
+ Firm.includes(:clients).map(&:name)
493
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
494
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Firm, :clients)
495
+
496
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
497
+ end
498
+ end
499
+ end
500
+
501
+ describe Bullet::Detector::Association, "has_one" do
502
+ context "company => address" do
503
+ it "should detect non preload association" do
504
+ Company.all.each do |company|
505
+ company.address.name
506
+ end
507
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
508
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
509
+
510
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Company, :address)
511
+ end
512
+
513
+ it "should detect preload association" do
514
+ Company.includes(:address).each do |company|
515
+ company.address.name
516
+ end
517
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
518
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
519
+
520
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
521
+ end
522
+
523
+ it "should not detect preload association" do
524
+ Company.all.map(&:name)
525
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
526
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
527
+
528
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
529
+ end
530
+
531
+ it "should detect unused preload association" do
532
+ Company.includes(:address).map(&:name)
533
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
534
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Company, :address)
535
+
536
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
537
+ end
538
+ end
539
+ end
540
+
541
+ describe Bullet::Detector::Association, "has_one => has_many" do
542
+ it "should not detect preload association" do
543
+ user = User.first
544
+ user.submission.replies.map(&:name)
545
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
546
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
547
+
548
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
549
+ end
550
+ end
551
+
552
+ describe Bullet::Detector::Association, "call one association that in possible objects" do
553
+ it "should not detect preload association" do
554
+ Post.all
555
+ Post.first.comments.map(&:name)
556
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
557
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
558
+
559
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
560
+ end
561
+ end
562
+
563
+ 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
569
+
570
+ document2 = Document.new(parent: document1)
571
+ document2.save
572
+ document2.parent
573
+
574
+ document1.children.each.first
575
+
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
+ end
582
+ end
583
+
584
+ describe Bullet::Detector::Association, "STI" do
585
+ context "page => author" do
586
+ it "should detect non preload associations" do
587
+ Page.all.each do |page|
588
+ page.author.name
589
+ end
590
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
591
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
592
+
593
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Page, :author)
594
+ end
595
+
596
+ it "should detect preload associations" do
597
+ Page.includes(:author).each do |page|
598
+ page.author.name
599
+ end
600
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
601
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
602
+
603
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
604
+ end
605
+
606
+ it "should detect unused preload associations" do
607
+ Page.includes(:author).map(&:name)
608
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
609
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Page, :author)
610
+
611
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
612
+ end
613
+
614
+ it "should not detect preload associations" do
615
+ Page.all.map(&:name)
616
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
617
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
618
+
619
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
620
+ end
621
+ end
622
+
623
+ context "disable n plus one query" do
624
+ before { Bullet.n_plus_one_query_enable = false }
625
+ after { Bullet.n_plus_one_query_enable = true }
626
+
627
+ it "should not detect n plus one query" do
628
+ Post.all.each do |post|
629
+ post.comments.map(&:name)
630
+ end
631
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
632
+
633
+ expect(Bullet::Detector::Association).not_to be_detecting_unpreloaded_association_for(Post, :comments)
634
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
635
+ end
636
+
637
+ it "should still detect unused eager loading" do
638
+ Post.includes(:comments).map(&:name)
639
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
640
+
641
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
642
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Post, :comments)
643
+ end
644
+ end
645
+
646
+ context "disable unused eager loading" do
647
+ before { Bullet.unused_eager_loading_enable = false }
648
+ after { Bullet.unused_eager_loading_enable = true }
649
+
650
+ it "should not detect unused eager loading" do
651
+ Post.includes(:comments).map(&:name)
652
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
653
+
654
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
655
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
656
+ end
657
+
658
+ it "should still detect n plus one query" do
659
+ Post.all.each do |post|
660
+ post.comments.map(&:name)
661
+ end
662
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
663
+
664
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
665
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
666
+ end
667
+ end
668
+
669
+ context "whitelist n plus one query" do
670
+ before { Bullet.add_whitelist :type => :n_plus_one_query, :class_name => "Post", :association => :comments }
671
+ after { Bullet.clear_whitelist }
672
+
673
+ it "should not detect n plus one query" do
674
+ Post.all.each do |post|
675
+ post.comments.map(&:name)
676
+ end
677
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
678
+
679
+ expect(Bullet::Detector::Association).not_to be_detecting_unpreloaded_association_for(Post, :comments)
680
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
681
+ end
682
+
683
+ it "should still detect unused eager loading" do
684
+ Post.includes(:comments).map(&:name)
685
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
686
+
687
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
688
+ expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Post, :comments)
689
+ end
690
+ end
691
+
692
+ context "whitelist unused eager loading" do
693
+ before { Bullet.add_whitelist :type => :unused_eager_loading, :class_name => "Post", :association => :comments }
694
+ after { Bullet.clear_whitelist }
695
+
696
+ it "should not detect unused eager loading" do
697
+ Post.includes(:comments).map(&:name)
698
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
699
+
700
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
701
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
702
+ end
703
+
704
+ it "should still detect n plus one query" do
705
+ Post.all.each do |post|
706
+ post.comments.map(&:name)
707
+ end
708
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
709
+
710
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
711
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
712
+ end
713
+ end
714
+ end
715
+ end
@@ -29,11 +29,20 @@ if !mongoid? && active_record?
29
29
  expect(Bullet.collected_counter_cache_notifications).to be_empty
30
30
  end
31
31
 
32
- it "should need counter cache for has_many through" do
33
- Client.all.each do |client|
34
- client.firms.size
32
+ if active_record5?
33
+ it "should not need counter cache for has_many through" do
34
+ Client.all.each do |client|
35
+ client.firms.size
36
+ end
37
+ expect(Bullet.collected_counter_cache_notifications).to be_empty
38
+ end
39
+ else
40
+ it "should need counter cache for has_many through" do
41
+ Client.all.each do |client|
42
+ client.firms.size
43
+ end
44
+ expect(Bullet.collected_counter_cache_notifications).not_to be_empty
35
45
  end
36
- expect(Bullet.collected_counter_cache_notifications).not_to be_empty
37
46
  end
38
47
 
39
48
  it "should not need counter cache with part of cities" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.14.10
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-23 00:00:00.000000000 Z
11
+ date: 2016-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -66,6 +66,7 @@ files:
66
66
  - Gemfile.rails-4.0
67
67
  - Gemfile.rails-4.1
68
68
  - Gemfile.rails-4.2
69
+ - Gemfile.rails-5.0
69
70
  - Guardfile
70
71
  - Hacking.md
71
72
  - MIT-LICENSE
@@ -78,6 +79,7 @@ files:
78
79
  - lib/bullet/active_record4.rb
79
80
  - lib/bullet/active_record41.rb
80
81
  - lib/bullet/active_record42.rb
82
+ - lib/bullet/active_record5.rb
81
83
  - lib/bullet/dependency.rb
82
84
  - lib/bullet/detector.rb
83
85
  - lib/bullet/detector/association.rb
@@ -124,6 +126,7 @@ files:
124
126
  - spec/bullet_spec.rb
125
127
  - spec/integration/active_record3/association_spec.rb
126
128
  - spec/integration/active_record4/association_spec.rb
129
+ - spec/integration/active_record5/association_spec.rb
127
130
  - spec/integration/counter_cache_spec.rb
128
131
  - spec/integration/mongoid/association_spec.rb
129
132
  - spec/models/address.rb
@@ -186,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
189
  version: 1.3.6
187
190
  requirements: []
188
191
  rubyforge_project:
189
- rubygems_version: 2.4.6
192
+ rubygems_version: 2.5.1
190
193
  signing_key:
191
194
  specification_version: 4
192
195
  summary: help to kill N+1 queries and unused eager loading.
@@ -210,6 +213,7 @@ test_files:
210
213
  - spec/bullet_spec.rb
211
214
  - spec/integration/active_record3/association_spec.rb
212
215
  - spec/integration/active_record4/association_spec.rb
216
+ - spec/integration/active_record5/association_spec.rb
213
217
  - spec/integration/counter_cache_spec.rb
214
218
  - spec/integration/mongoid/association_spec.rb
215
219
  - spec/models/address.rb