bullet 5.0.0 → 5.1.1

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: d5439116cdedcd96dfad6dfd315eaf47ee815153
4
- data.tar.gz: 9542679b93fa670fbf8b014fb0cbd3adb13a30d8
3
+ metadata.gz: 0158f6af4990b365de2859cea97877e5b290ea83
4
+ data.tar.gz: cd8914938d74645ae75d01ee8feaf23e38f8d028
5
5
  SHA512:
6
- metadata.gz: 4704ead627526344ab065d5d0a9bd2f3516165f664d9ab97aca3dd576c55ecc75450636daceebe21d100562be45c5e9352296ea0cd5856b0a4205be2120751cb
7
- data.tar.gz: 6b3d52be604e5188920592e6b3952d2a683364631739c097b619b151f9131b911454452eae824e13493a4866ff767eb9ba61da3a98097aa3042e498faf74bdd6
6
+ metadata.gz: 9e92c13202832afaaf604072c06e695cfe552d5626318d6c625cebacdfdc13ecc14aeed8c64d6df483b4c05caa090ecee01e613228dae6466edbe66803e7333a
7
+ data.tar.gz: 7d365b32c075a00733e4c70daedcfbca042cb2334a77c6e132fc31b33e9dd23aaca8a65eaa1578ffba2f106303cf572e84e41b7fd6c7c61a239b2dbea9fcaabe
data/.travis.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
+ - 1.9.3
4
5
  - 2.0
5
6
  - 2.1
6
7
  - 2.2
@@ -28,8 +29,38 @@ services:
28
29
  - mongodb
29
30
  matrix:
30
31
  exclude:
32
+ - rvm: 1.9.3
33
+ gemfile: Gemfile.rails-4.0
34
+ - rvm: 1.9.3
35
+ gemfile: Gemfile.rails-4.1
36
+ - rvm: 1.9.3
37
+ gemfile: Gemfile.rails-4.2
38
+ - rvm: 1.9.3
39
+ gemfile: Gemfile.rails-5.0
40
+ - rvm: 1.9.3
41
+ gemfile: Gemfile.mongoid-2.4
42
+ - rvm: 1.9.3
43
+ gemfile: Gemfile.mongoid-2.5
44
+ - rvm: 1.9.3
45
+ gemfile: Gemfile.mongoid-2.6
46
+ - rvm: 1.9.3
47
+ gemfile: Gemfile.mongoid-2.7
48
+ - rvm: 1.9.3
49
+ gemfile: Gemfile.mongoid-2.8
50
+ - rvm: 1.9.3
51
+ gemfile: Gemfile.mongoid-3.0
52
+ - rvm: 1.9.3
53
+ gemfile: Gemfile.mongoid-3.1
54
+ - rvm: 1.9.3
55
+ gemfile: Gemfile.mongoid-4.0
56
+ - rvm: 1.9.3
57
+ gemfile: Gemfile.mongoid-5.0
58
+ - rvm: 2.0
59
+ gemfile: Gemfile.rails-3.0
31
60
  - rvm: 2.0
32
61
  gemfile: Gemfile.rails-5.0
62
+ - rvm: 2.1
63
+ gemfile: Gemfile.rails-3.0
33
64
  - rvm: 2.1
34
65
  gemfile: Gemfile.rails-5.0
35
66
  - rvm: 2.2
data/CHANGELOG.md CHANGED
@@ -1,55 +1,36 @@
1
1
  # Next Release
2
2
 
3
- ## 5.0.0 (01/06/2015)
3
+ ## 5.1.1
4
4
 
5
- * Support Rails 5.0.0.beta1
5
+ * Fix `has_cached_counter?` is not defined in HABTM #297
6
+ * Fix false alert if preloaded association has no records #260
6
7
 
7
- ## 4.14.10
8
+ ## 5.1.0 (05/21/2016)
8
9
 
9
- * Fix `has_many :through` infinite loop issue
10
+ * Fix false alert when `empty?` used with `counter_cache`
11
+ * Fix `alias_method_chain` deprecation for rails 5
12
+ * Add response handling for non-Rails Rack responses
13
+ * Fix false alert when querying immediately after creation
14
+ * Fix UnusedEagerLoading bug when multiple eager loading query include same objects
10
15
 
11
- ## 4.14.9
16
+ ## 5.0.0 (01/06/2016)
12
17
 
18
+ * Support Rails 5.0.0.beta1
19
+ * Fix `has_many :through` infinite loop issue
13
20
  * Support mongoid 5.0.0
14
21
  * Do not report association queries immediately after object creation to
15
22
  require a preload
16
23
  * Detect `counter_cache` for `has_many :through` association
17
-
18
- ## 4.14.8
19
-
20
- * compatible with `composite_primary_keys` gem
21
-
22
- ## 4.14.7
23
-
24
+ * Compatible with `composite_primary_keys` gem
24
25
  * Fix AR 4.2 SingularAssociation#reader result can be nil
25
26
  * `perform_out_of_channel_notifications` should always be triggered
26
-
27
- ## 4.14.6
28
-
29
27
  * Fix false positive with `belongs_to` -> `belongs_to` for active\_record 4.2
30
28
  * Activate active\_record hacks only when Bullet already start
31
-
32
- ## 4.14.5
33
-
34
29
  * Don't execute query when running `to_sql`
35
30
  * Send backtrace to `uniform_notifier`
36
31
  * Fix sse response check
37
32
  * Dynamically delegate available notifiers to UniformNotifier
38
-
39
- ## 4.14.4
40
-
41
- * Fix false N + 1 warnings on Rails 4.2
42
-
43
- ## 4.14.3
44
-
45
- * Fix false positive on create
46
-
47
- ## 4.14.2
48
-
49
33
  * Hotfix nil object when `add_impossible_object`
50
-
51
- ## 4.14.1
52
-
53
34
  * Fix `has_one` then `has_many` associations in rails 4.2
54
35
  * Append js and dom to html body in proper position
55
36
 
data/Gemfile.mongoid-5.0 CHANGED
@@ -5,7 +5,7 @@ gemspec
5
5
  gem 'rails', '~> 4.0.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
- gem 'mongoid', '~> 5.0.0.beta', github: 'mongoid'
8
+ gem 'mongoid', '~> 5.0.0'
9
9
 
10
10
  gem "rspec"
11
11
 
data/Gemfile.rails-3.0 CHANGED
@@ -6,6 +6,7 @@ gem 'rails', '~> 3.0.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
+ gem 'tins', '~> 1.6.0', platforms: [:ruby_19]
9
10
 
10
11
  gem "rspec"
11
12
 
data/Gemfile.rails-3.1 CHANGED
@@ -6,6 +6,7 @@ gem 'rails', '~> 3.1.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
+ gem 'tins', '~> 1.6.0', platforms: [:ruby_19]
9
10
 
10
11
  gem "rspec"
11
12
 
data/Gemfile.rails-3.2 CHANGED
@@ -6,6 +6,7 @@ gem 'rails', '~> 3.2.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
+ gem 'tins', '~> 1.6.0', platforms: [:ruby_19]
9
10
 
10
11
  gem "rspec"
11
12
 
data/Gemfile.rails-4.0 CHANGED
@@ -6,6 +6,7 @@ gem 'rails', '~> 4.0.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
+ gem 'tins', '~> 1.6.0', platforms: [:ruby_19]
9
10
 
10
11
  gem "rspec"
11
12
 
data/Gemfile.rails-4.1 CHANGED
@@ -6,6 +6,7 @@ gem 'rails', '~> 4.1.0'
6
6
  gem 'sqlite3'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
+ gem 'tins', '~> 1.6.0', platforms: [:ruby_19]
9
10
 
10
11
  gem "rspec"
11
12
 
data/Gemfile.rails-4.2 CHANGED
@@ -6,6 +6,7 @@ gem 'rails', '~> 4.2.0'
6
6
  gem 'sqlite3'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
+ gem 'tins', '~> 1.6.0', platforms: [:ruby_19]
9
10
 
10
11
  gem "rspec"
11
12
 
data/Hacking.md CHANGED
@@ -23,6 +23,7 @@ Notification instances contain the message that will be displayed, and will
23
23
  use a Presenter class to display their message to the user.
24
24
 
25
25
  So the flow of a request goes like this:
26
+
26
27
  1. Bullet.start_request is called, which resets all the detectors and empties
27
28
  the notification collector
28
29
  2. The request is handled by Rails, and the installed ActiveRecord extensions
data/README.md CHANGED
@@ -238,7 +238,9 @@ Bullet outputs some details info, to enable debug mode, set
238
238
 
239
239
  ## Demo
240
240
 
241
- Bullet is designed to function as you browse through your application in development. To see it in action, follow these steps to create, detect, and fix example query problems.
241
+ Bullet is designed to function as you browse through your application in development. To see it in action,
242
+ you can visit [https://github.com/flyerhzm/bullet_test](https://github.com/flyerhzm/bullet_test) or
243
+ follow these steps to create, detect, and fix example query problems.
242
244
 
243
245
  1\. Create an example application
244
246
 
@@ -458,4 +460,4 @@ Meanwhile, there's a line appended to `log/bullet.log`
458
460
  Post => [:comments]
459
461
  ```
460
462
 
461
- Copyright (c) 2009 - 2015 Richard Huang (flyerhzm@gmail.com), released under the MIT license
463
+ Copyright (c) 2009 - 2016 Richard Huang (flyerhzm@gmail.com), released under the MIT license
data/bullet.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.required_rubygems_version = ">= 1.3.6"
19
19
 
20
20
  s.add_runtime_dependency "activesupport", ">= 3.0.0"
21
- s.add_runtime_dependency "uniform_notifier", "~> 1.9.0"
21
+ s.add_runtime_dependency "uniform_notifier", "~> 1.10.0"
22
22
 
23
23
  s.files = `git ls-files`.split("\n")
24
24
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -23,6 +23,24 @@ module Bullet
23
23
  end
24
24
  end
25
25
 
26
+ ::ActiveRecord::Persistence.class_eval do
27
+ alias_method :origin_save, :save
28
+ def save(*args, &proc)
29
+ was_new_record = new_record?
30
+ origin_save(*args, &proc).tap do |result|
31
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
32
+ end
33
+ end
34
+
35
+ alias_method :origin_save!, :save!
36
+ def save!(*args, &proc)
37
+ was_new_record = new_record?
38
+ origin_save!(*args, &proc).tap do |result|
39
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
40
+ end
41
+ end
42
+ end
43
+
26
44
  ::ActiveRecord::AssociationPreload::ClassMethods.class_eval do
27
45
  alias_method :origin_preload_associations, :preload_associations
28
46
  # include query for one to many associations.
@@ -116,20 +134,32 @@ module Bullet
116
134
  origin_last(*args)
117
135
  end
118
136
 
137
+ alias_method :origin_include?, :include?
138
+ def include?(object)
139
+ if Bullet.start?
140
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
141
+ end
142
+ origin_include?(object)
143
+ end
144
+ end
145
+
146
+ ::ActiveRecord::Associations::HasManyAssociation.class_eval do
119
147
  alias_method :origin_empty?, :empty?
120
148
  def empty?
121
- if Bullet.start?
149
+ if Bullet.start? && !has_cached_counter?
122
150
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
123
151
  end
124
152
  origin_empty?
125
153
  end
154
+ end
126
155
 
127
- alias_method :origin_include?, :include?
128
- def include?(object)
156
+ ::ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
157
+ alias_method :origin_empty?, :empty?
158
+ def empty?
129
159
  if Bullet.start?
130
160
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
131
161
  end
132
- origin_include?(object)
162
+ origin_empty?
133
163
  end
134
164
  end
135
165
 
@@ -21,6 +21,24 @@ module Bullet
21
21
  end
22
22
  end
23
23
 
24
+ ::ActiveRecord::Persistence.class_eval do
25
+ alias_method :origin_save, :save
26
+ def save(*args, &proc)
27
+ was_new_record = new_record?
28
+ origin_save(*args, &proc).tap do |result|
29
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
30
+ end
31
+ end
32
+
33
+ alias_method :origin_save!, :save!
34
+ def save!(*args, &proc)
35
+ was_new_record = new_record?
36
+ origin_save!(*args, &proc).tap do |result|
37
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
38
+ end
39
+ end
40
+ end
41
+
24
42
  ::ActiveRecord::Associations::Preloader.class_eval do
25
43
  # include query for one to many associations.
26
44
  # keep this eager loadings.
@@ -98,20 +116,32 @@ module Bullet
98
116
  origin_load_target
99
117
  end
100
118
 
119
+ alias_method :origin_include?, :include?
120
+ def include?(object)
121
+ if Bullet.start?
122
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
123
+ end
124
+ origin_include?(object)
125
+ end
126
+ end
127
+
128
+ ::ActiveRecord::Associations::HasManyAssociation.class_eval do
101
129
  alias_method :origin_empty?, :empty?
102
130
  def empty?
103
- if Bullet.start?
131
+ if Bullet.start? && !has_cached_counter?(@reflection)
104
132
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
105
133
  end
106
134
  origin_empty?
107
135
  end
136
+ end
108
137
 
109
- alias_method :origin_include?, :include?
110
- def include?(object)
138
+ ::ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
139
+ alias_method :origin_empty?, :empty?
140
+ def empty?
111
141
  if Bullet.start?
112
142
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
113
143
  end
114
- origin_include?(object)
144
+ origin_empty?
115
145
  end
116
146
  end
117
147
 
@@ -29,6 +29,14 @@ module Bullet
29
29
  end
30
30
  end
31
31
  alias_method_chain :save, :bullet
32
+
33
+ def save_with_bullet!(*args, &proc)
34
+ was_new_record = new_record?
35
+ save_without_bullet!(*args, &proc).tap do |result|
36
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
37
+ end
38
+ end
39
+ alias_method_chain :save!, :bullet
32
40
  end
33
41
 
34
42
  ::ActiveRecord::Associations::Preloader.class_eval do
@@ -108,20 +116,32 @@ module Bullet
108
116
  origin_load_target
109
117
  end
110
118
 
119
+ alias_method :origin_include?, :include?
120
+ def include?(object)
121
+ if Bullet.start?
122
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
123
+ end
124
+ origin_include?(object)
125
+ end
126
+ end
127
+
128
+ ::ActiveRecord::Associations::HasManyAssociation.class_eval do
111
129
  alias_method :origin_empty?, :empty?
112
130
  def empty?
113
- if Bullet.start?
131
+ if Bullet.start? && !has_cached_counter?(@reflection)
114
132
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
115
133
  end
116
134
  origin_empty?
117
135
  end
136
+ end
118
137
 
119
- alias_method :origin_include?, :include?
120
- def include?(object)
138
+ ::ActiveRecord::Associations::HasAndBelongsToManyAssociation.class_eval do
139
+ alias_method :origin_empty?, :empty?
140
+ def empty?
121
141
  if Bullet.start?
122
142
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
123
143
  end
124
- origin_include?(object)
144
+ origin_empty?
125
145
  end
126
146
  end
127
147
 
@@ -31,6 +31,14 @@ module Bullet
31
31
  end
32
32
  end
33
33
  alias_method_chain :save, :bullet
34
+
35
+ def save_with_bullet!(*args, &proc)
36
+ was_new_record = new_record?
37
+ save_without_bullet!(*args, &proc).tap do |result|
38
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
39
+ end
40
+ end
41
+ alias_method_chain :save!, :bullet
34
42
  end
35
43
 
36
44
  ::ActiveRecord::Associations::Preloader.class_eval do
@@ -113,7 +121,7 @@ module Bullet
113
121
 
114
122
  alias_method :origin_empty?, :empty?
115
123
  def empty?
116
- if Bullet.start?
124
+ if Bullet.start? && !has_cached_counter?(@reflection)
117
125
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
118
126
  end
119
127
  origin_empty?
@@ -29,6 +29,14 @@ module Bullet
29
29
  end
30
30
  end
31
31
  alias_method_chain :save, :bullet
32
+
33
+ def save_with_bullet!(*args, &proc)
34
+ was_new_record = new_record?
35
+ save_without_bullet!(*args, &proc).tap do |result|
36
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
37
+ end
38
+ end
39
+ alias_method_chain :save!, :bullet
32
40
  end
33
41
 
34
42
  ::ActiveRecord::Relation.class_eval do
@@ -127,7 +135,9 @@ module Bullet
127
135
  records = origin_load_target
128
136
 
129
137
  if Bullet.start?
130
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
138
+ if records.size > 1
139
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
140
+ end
131
141
  if records.first.class.name !~ /^HABTM_/
132
142
  if records.size > 1
133
143
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
@@ -143,7 +153,7 @@ module Bullet
143
153
 
144
154
  alias_method :origin_empty?, :empty?
145
155
  def empty?
146
- if Bullet.start?
156
+ if Bullet.start? && !has_cached_counter?(@reflection)
147
157
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
148
158
  end
149
159
  origin_empty?
@@ -183,7 +193,7 @@ module Bullet
183
193
  Thread.current[:bullet_collection_empty] = true
184
194
  result = origin_many_empty?
185
195
  Thread.current[:bullet_collection_empty] = nil
186
- if Bullet.start?
196
+ if Bullet.start? && !has_cached_counter?(@reflection)
187
197
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
188
198
  end
189
199
  result
@@ -1,4 +1,20 @@
1
1
  module Bullet
2
+ module SaveWithBulletSupport
3
+ def save(*args)
4
+ was_new_record = new_record?
5
+ super(*args).tap do |result|
6
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
7
+ end
8
+ end
9
+
10
+ def save!(*args)
11
+ was_new_record = new_record?
12
+ super(*args).tap do |result|
13
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
14
+ end
15
+ end
16
+ end
17
+
2
18
  module ActiveRecord
3
19
  def self.enable
4
20
  require 'active_record'
@@ -21,15 +37,7 @@ module Bullet
21
37
  end
22
38
  end
23
39
 
24
- ::ActiveRecord::Persistence.class_eval do
25
- def save_with_bullet(*args, &proc)
26
- was_new_record = new_record?
27
- save_without_bullet(*args, &proc).tap do |result|
28
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
29
- end
30
- end
31
- alias_method_chain :save, :bullet
32
- end
40
+ ::ActiveRecord::Base.prepend(SaveWithBulletSupport)
33
41
 
34
42
  ::ActiveRecord::Relation.class_eval do
35
43
  alias_method :origin_to_a, :to_a
@@ -135,7 +143,9 @@ module Bullet
135
143
  records = origin_load_target
136
144
 
137
145
  if Bullet.start?
138
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
146
+ if records.size > 1
147
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
148
+ end
139
149
  if records.first.class.name !~ /^HABTM_/
140
150
  if records.size > 1
141
151
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
@@ -151,7 +161,7 @@ module Bullet
151
161
 
152
162
  alias_method :origin_empty?, :empty?
153
163
  def empty?
154
- if Bullet.start?
164
+ if Bullet.start? && !@reflection.has_cached_counter?
155
165
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
156
166
  end
157
167
  origin_empty?
@@ -191,7 +201,7 @@ module Bullet
191
201
  Thread.current[:bullet_collection_empty] = true
192
202
  result = origin_many_empty?
193
203
  Thread.current[:bullet_collection_empty] = nil
194
- if Bullet.start?
204
+ if Bullet.start? && !@reflection.has_cached_counter?
195
205
  Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
196
206
  end
197
207
  result
@@ -27,27 +27,25 @@ module Bullet
27
27
  Bullet.debug("Detector::UnusedEagerLoading#add_eager_loadings", "objects: #{objects.map(&:bullet_key).join(', ')}, associations: #{associations}")
28
28
  bullet_keys = objects.map(&:bullet_key)
29
29
 
30
- to_add = nil
31
- to_merge, to_delete = [], []
30
+ to_add, to_merge, to_delete = [], [], []
32
31
  eager_loadings.each do |k, v|
33
32
  key_objects_overlap = k & bullet_keys
34
33
 
35
34
  next if key_objects_overlap.empty?
36
35
 
36
+ bullet_keys = bullet_keys - k
37
37
  if key_objects_overlap == k
38
- to_add = [k, associations]
39
- break
38
+ to_add << [k, associations]
40
39
  else
41
40
  to_merge << [key_objects_overlap, ( eager_loadings[k].dup << associations )]
42
41
 
43
- keys_without_objects = k - bullet_keys
42
+ keys_without_objects = k - key_objects_overlap
44
43
  to_merge << [keys_without_objects, eager_loadings[k]]
45
44
  to_delete << k
46
- bullet_keys = bullet_keys - k
47
45
  end
48
46
  end
49
47
 
50
- eager_loadings.add(*to_add) if to_add
48
+ to_add.each { |k, val| eager_loadings.add k, val }
51
49
  to_merge.each { |k, val| eager_loadings.merge k, val }
52
50
  to_delete.each { |k| eager_loadings.delete k }
53
51
 
@@ -57,11 +57,11 @@ module Bullet
57
57
  end
58
58
 
59
59
  def eql?(other)
60
- klazz_associations_str == other.klazz_associations_str
60
+ self.class == other.class && klazz_associations_str == other.klazz_associations_str
61
61
  end
62
62
 
63
63
  def hash
64
- klazz_associations_str.hash
64
+ [self.class, klazz_associations_str].hash
65
65
  end
66
66
 
67
67
  protected
data/lib/bullet/rack.rb CHANGED
@@ -67,7 +67,7 @@ module Bullet
67
67
  end
68
68
 
69
69
  def response_body(response)
70
- if rails?
70
+ if response.respond_to?(:body)
71
71
  Array === response.body ? response.body.first : response.body
72
72
  else
73
73
  response.first
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Bullet
3
- VERSION = "5.0.0"
3
+ VERSION = "5.1.1"
4
4
  end
data/lib/bullet.rb CHANGED
@@ -82,8 +82,8 @@ module Bullet
82
82
 
83
83
  def add_whitelist(options)
84
84
  reset_whitelist
85
- @whitelist[options[:type]][options[:class_name].classify] ||= []
86
- @whitelist[options[:type]][options[:class_name].classify] << options[:association].to_sym
85
+ @whitelist[options[:type]][options[:class_name]] ||= []
86
+ @whitelist[options[:type]][options[:class_name]] << options[:association].to_sym
87
87
  end
88
88
 
89
89
  def get_whitelist_associations(type, class_name)
@@ -190,17 +190,22 @@ module Bullet
190
190
  end
191
191
 
192
192
  def profile
193
+ return_value = nil
193
194
  if Bullet.enable?
194
195
  begin
195
196
  Bullet.start_request
196
197
 
197
- yield
198
+ return_value = yield
198
199
 
199
200
  Bullet.perform_out_of_channel_notifications if Bullet.notification?
200
201
  ensure
201
202
  Bullet.end_request
202
203
  end
204
+ else
205
+ return_value = yield
203
206
  end
207
+
208
+ return_value
204
209
  end
205
210
 
206
211
  private
@@ -5,7 +5,8 @@ module Bullet
5
5
  describe UnusedEagerLoading do
6
6
  before(:all) do
7
7
  @post = Post.first
8
- @post2 = Post.last
8
+ @post2 = Post.all[1]
9
+ @post3 = Post.last
9
10
  end
10
11
 
11
12
  context ".call_associations" do
@@ -72,7 +73,18 @@ module Bullet
72
73
  UnusedEagerLoading.add_eager_loadings([@post, @post2], :association2)
73
74
  expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
74
75
  expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association2)
75
- expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key, @post2.bullet_key], :association2)
76
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post2.bullet_key], :association2)
77
+ end
78
+
79
+ it "should vmerge objects recursively, associations pair for existing eager_loadings" do
80
+ UnusedEagerLoading.add_eager_loadings([@post, @post2], :association1)
81
+ UnusedEagerLoading.add_eager_loadings([@post, @post3], :association1)
82
+ UnusedEagerLoading.add_eager_loadings([@post, @post3], :association2)
83
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association1)
84
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post.bullet_key], :association2)
85
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post2.bullet_key], :association1)
86
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post3.bullet_key], :association1)
87
+ expect(UnusedEagerLoading.send(:eager_loadings)).to be_include([@post3.bullet_key], :association2)
76
88
  end
77
89
 
78
90
  it "should delete objects, associations pair for existing eager_loadings" do
@@ -93,5 +93,36 @@ module Bullet
93
93
  end
94
94
  end
95
95
  end
96
+
97
+ describe "#response_body" do
98
+ let(:response) { double }
99
+ let(:body_string) { "<html><body>My Body</body></html>" }
100
+
101
+ context "when `response` responds to `body`" do
102
+ before { allow(response).to receive(:body).and_return(body) }
103
+
104
+ context "when `body` returns an Array" do
105
+ let(:body) { [body_string, 'random string'] }
106
+ it "should return the plain body string" do
107
+ expect(middleware.response_body(response)).to eq body_string
108
+ end
109
+ end
110
+
111
+ context "when `body` does not return an Array" do
112
+ let(:body) { body_string }
113
+ it "should return the plain body string" do
114
+ expect(middleware.response_body(response)).to eq body_string
115
+ end
116
+ end
117
+ end
118
+
119
+ context "when `response` does not respond to `body`" do
120
+ before { allow(response).to receive(:first).and_return(body_string) }
121
+
122
+ it "should return the plain body string" do
123
+ expect(middleware.response_body(response)).to eq body_string
124
+ end
125
+ end
126
+ end
96
127
  end
97
128
  end
data/spec/bullet_spec.rb CHANGED
@@ -85,4 +85,13 @@ describe Bullet, focused: true do
85
85
  end
86
86
  end
87
87
  end
88
+
89
+ describe '#add_whitelist' do
90
+ context "for 'special' class names" do
91
+ it 'is added to the whitelist successfully' do
92
+ Bullet.add_whitelist(:type => :n_plus_one_query, :class_name => 'Klass', :association => :department)
93
+ expect(Bullet.get_whitelist_associations(:n_plus_one_query, 'Klass')).to include :department
94
+ end
95
+ end
96
+ end
88
97
  end
@@ -72,6 +72,16 @@ if !mongoid? && active_record3?
72
72
 
73
73
  expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
74
74
  end
75
+
76
+ it "should not detect unused preload person => pets with empty?" do
77
+ Person.all.each do |person|
78
+ person.pets.empty?
79
+ end
80
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
81
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
82
+
83
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
84
+ end
75
85
  end
76
86
 
77
87
  context "category => posts => comments" do
@@ -204,7 +214,7 @@ if !mongoid? && active_record3?
204
214
  context "post => comment" do
205
215
  it "should detect unused preload with post => comments" do
206
216
  Post.includes(:comments).each do |post|
207
- post.comments.first.name
217
+ post.comments.first.name if post.comments.first
208
218
  end
209
219
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
210
220
  expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :comments)
@@ -443,6 +453,16 @@ if !mongoid? && active_record3?
443
453
 
444
454
  expect(Bullet::Detector::Association).to be_completely_preloading_associations
445
455
  end
456
+
457
+ it "should detect non preload student => teachers with empty?" do
458
+ Student.all.each do |student|
459
+ student.teachers.empty?
460
+ end
461
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
462
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
463
+
464
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Student, :teachers)
465
+ end
446
466
  end
447
467
  end
448
468
 
@@ -537,6 +557,50 @@ if !mongoid? && active_record3?
537
557
  end
538
558
  end
539
559
 
560
+ describe Bullet::Detector::Association, "query immediately after creation" do
561
+ context "with save" do
562
+ context "document => children" do
563
+ it 'should not detect non preload associations' do
564
+ document1 = Document.new
565
+ document1.children.build
566
+ document1.save
567
+
568
+ document2 = Document.new(parent: document1)
569
+ document2.save
570
+ document2.parent
571
+
572
+ document1.children.each.first
573
+
574
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
575
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
576
+
577
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
578
+ end
579
+ end
580
+ end
581
+
582
+ context "with save!" do
583
+ context "document => children" do
584
+ it 'should not detect non preload associations' do
585
+ document1 = Document.new
586
+ document1.children.build
587
+ document1.save!
588
+
589
+ document2 = Document.new(parent: document1)
590
+ document2.save!
591
+ document2.parent
592
+
593
+ document1.children.each.first
594
+
595
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
596
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
597
+
598
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
599
+ end
600
+ end
601
+ end
602
+ end
603
+
540
604
  describe Bullet::Detector::Association, "STI" do
541
605
  context "page => author" do
542
606
  it "should detect non preload associations" do
@@ -72,6 +72,16 @@ if !mongoid? && active_record4?
72
72
 
73
73
  expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
74
74
  end
75
+
76
+ it "should not detect unused preload person => pets with empty?" do
77
+ Person.all.each do |person|
78
+ person.pets.empty?
79
+ end
80
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
81
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
82
+
83
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
84
+ end
75
85
  end
76
86
 
77
87
  context "category => posts => comments" do
@@ -204,7 +214,7 @@ if !mongoid? && active_record4?
204
214
  context "post => comment" do
205
215
  it "should detect unused preload with post => comments" do
206
216
  Post.includes(:comments).each do |post|
207
- post.comments.first.name
217
+ post.comments.first.name if post.comments.first
208
218
  end
209
219
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
210
220
  expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :comments)
@@ -455,6 +465,16 @@ if !mongoid? && active_record4?
455
465
 
456
466
  expect(Bullet::Detector::Association).to be_completely_preloading_associations
457
467
  end
468
+
469
+ it "should detect non preload student => teachers with empty?" do
470
+ Student.all.each do |student|
471
+ student.teachers.empty?
472
+ end
473
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
474
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
475
+
476
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Student, :teachers)
477
+ end
458
478
  end
459
479
  end
460
480
 
@@ -561,22 +581,45 @@ if !mongoid? && active_record4?
561
581
  end
562
582
 
563
583
  describe Bullet::Detector::Association, "query immediately after creation" do
564
- context "document => children" do
565
- it 'should not detect non preload associations' do
566
- document1 = Document.new
567
- document1.children.build
568
- document1.save
584
+ context "with save" do
585
+ context "document => children" do
586
+ it 'should not detect non preload associations' do
587
+ document1 = Document.new
588
+ document1.children.build
589
+ document1.save
569
590
 
570
- document2 = Document.new(parent: document1)
571
- document2.save
572
- document2.parent
591
+ document2 = Document.new(parent: document1)
592
+ document2.save
593
+ document2.parent
573
594
 
574
- document1.children.each.first
595
+ document1.children.each.first
575
596
 
576
- Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
577
- expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
597
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
598
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
578
599
 
579
- expect(Bullet::Detector::Association).to be_completely_preloading_associations
600
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
601
+ end
602
+ end
603
+ end
604
+
605
+ context "with save!" do
606
+ context "document => children" do
607
+ it 'should not detect non preload associations' do
608
+ document1 = Document.new
609
+ document1.children.build
610
+ document1.save!
611
+
612
+ document2 = Document.new(parent: document1)
613
+ document2.save!
614
+ document2.parent
615
+
616
+ document1.children.each.first
617
+
618
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
619
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
620
+
621
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
622
+ end
580
623
  end
581
624
  end
582
625
  end
@@ -72,6 +72,16 @@ if !mongoid? && active_record5?
72
72
 
73
73
  expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Post, :comments)
74
74
  end
75
+
76
+ it "should not detect unused preload person => pets with empty?" do
77
+ Person.all.each do |person|
78
+ person.pets.empty?
79
+ end
80
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
81
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
82
+
83
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
84
+ end
75
85
  end
76
86
 
77
87
  context "category => posts => comments" do
@@ -204,7 +214,7 @@ if !mongoid? && active_record5?
204
214
  context "post => comment" do
205
215
  it "should detect unused preload with post => comments" do
206
216
  Post.includes(:comments).each do |post|
207
- post.comments.first.name
217
+ post.comments.first.name if post.comments.first
208
218
  end
209
219
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
210
220
  expect(Bullet::Detector::Association).not_to be_unused_preload_associations_for(Post, :comments)
@@ -455,6 +465,16 @@ if !mongoid? && active_record5?
455
465
 
456
466
  expect(Bullet::Detector::Association).to be_completely_preloading_associations
457
467
  end
468
+
469
+ it "should detect non preload student => teachers with empty?" do
470
+ Student.all.each do |student|
471
+ student.teachers.empty?
472
+ end
473
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
474
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
475
+
476
+ expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(Student, :teachers)
477
+ end
458
478
  end
459
479
  end
460
480
 
@@ -561,22 +581,45 @@ if !mongoid? && active_record5?
561
581
  end
562
582
 
563
583
  describe Bullet::Detector::Association, "query immediately after creation" do
564
- context "document => children" do
565
- it 'should not detect non preload associations' do
566
- document1 = Document.new
567
- document1.children.build
568
- document1.save
584
+ context "with save" do
585
+ context "document => children" do
586
+ it 'should not detect non preload associations' do
587
+ document1 = Document.new
588
+ document1.children.build
589
+ document1.save
569
590
 
570
- document2 = Document.new(parent: document1)
571
- document2.save
572
- document2.parent
591
+ document2 = Document.new(parent: document1)
592
+ document2.save
593
+ document2.parent
573
594
 
574
- document1.children.each.first
595
+ document1.children.each.first
575
596
 
576
- Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
577
- expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
597
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
598
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
578
599
 
579
- expect(Bullet::Detector::Association).to be_completely_preloading_associations
600
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
601
+ end
602
+ end
603
+ end
604
+
605
+ context "with save!" do
606
+ context "document => children" do
607
+ it 'should not detect non preload associations' do
608
+ document1 = Document.new
609
+ document1.children.build
610
+ document1.save!
611
+
612
+ document2 = Document.new(parent: document1)
613
+ document2.save!
614
+ document2.parent
615
+
616
+ document1.children.each.first
617
+
618
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
619
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
620
+
621
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
622
+ end
580
623
  end
581
624
  end
582
625
  end
@@ -16,6 +16,7 @@ module Support
16
16
  post1 = category1.posts.create(:name => 'first', :writer => writer1)
17
17
  post1a = category1.posts.create(:name => 'like first', :writer => writer2, active: false)
18
18
  post2 = category2.posts.create(:name => 'second', :writer => writer2)
19
+ post3 = category2.posts.create(:name => 'third', :writer => writer2)
19
20
 
20
21
  comment1 = post1.comments.create(:name => 'first', :author => writer1)
21
22
  comment2 = post1.comments.create(:name => 'first2', :author => writer1)
data/test.sh CHANGED
@@ -1,5 +1,6 @@
1
1
  #bundle update rails && bundle exec rspec spec
2
2
  #BUNDLE_GEMFILE=Gemfile.mongoid bundle update mongoid && BUNDLE_GEMFILE=Gemfile.mongoid bundle exec rspec spec
3
+ BUNDLE_GEMFILE=Gemfile.rails-5.0 bundle && BUNDLE_GEMFILE=Gemfile.rails-5.0 bundle exec rspec spec
3
4
  BUNDLE_GEMFILE=Gemfile.rails-4.2 bundle && BUNDLE_GEMFILE=Gemfile.rails-4.2 bundle exec rspec spec
4
5
  BUNDLE_GEMFILE=Gemfile.rails-4.1 bundle && BUNDLE_GEMFILE=Gemfile.rails-4.1 bundle exec rspec spec
5
6
  BUNDLE_GEMFILE=Gemfile.rails-4.0 bundle && BUNDLE_GEMFILE=Gemfile.rails-4.0 bundle exec rspec spec
data/update.sh CHANGED
@@ -1,3 +1,4 @@
1
+ BUNDLE_GEMFILE=Gemfile.rails-5.0 bundle update
1
2
  BUNDLE_GEMFILE=Gemfile.rails-4.2 bundle update
2
3
  BUNDLE_GEMFILE=Gemfile.rails-4.1 bundle update
3
4
  BUNDLE_GEMFILE=Gemfile.rails-4.0 bundle update
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: 5.0.0
4
+ version: 5.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-05 00:00:00.000000000 Z
11
+ date: 2016-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.9.0
33
+ version: 1.10.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.9.0
40
+ version: 1.10.0
41
41
  description: help to kill N+1 queries and unused eager loading.
42
42
  email:
43
43
  - flyerhzm@gmail.com