bullet 4.14.10 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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