bullet 4.14.0 → 4.14.5

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: cb37955eb9271242e6c93d070639487d27c41cc4
4
- data.tar.gz: 3dcfaee4517be454ae076b8707b479357aef4810
3
+ metadata.gz: 6a56f8b0100130149fc7c45ceb660b4b100b84b8
4
+ data.tar.gz: 44a4a67d0ab54bbc6ab8cfef656257e40131e7ab
5
5
  SHA512:
6
- metadata.gz: aad803335d34af96636af55b2db42e93770c1d989485bad7bcd6a5ac6b78c1cd95d5c133913d2fb606dd9cfedec078785a83d175dac42ebd408595866b791679
7
- data.tar.gz: e53e36ef7782a6e94079b128eaebecde19501ce26c0204dd35dbc7df53b81313d0f8fa22c0a445c1f10f5f163cf23afcaa29c998279963667ca7b7f34cdc7c66
6
+ metadata.gz: bdb47a4a12f599a6c35113a13ba9ed3559c220e06731beb2ff86d4bec9de0a019425c47d3b19c22e987d7106a930a15c985c56f057edd521a6a5000a76c126d8
7
+ data.tar.gz: 872c82a3e4d7ce373064c7738a45a012e1a001c35b428c49380635723d119bb3828a48e336eed733cdd2bf48905f6ad627dc6061a20b51ebf0b294aa093ca3a4
data/.travis.yml CHANGED
@@ -1,6 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1.2
3
+ - 2.0
4
+ - 2.1
5
+ - 2.2
4
6
  gemfile:
5
7
  - Gemfile.rails-4.2
6
8
  - Gemfile.rails-4.1
@@ -8,6 +10,7 @@ gemfile:
8
10
  - Gemfile.rails-3.2
9
11
  - Gemfile.rails-3.1
10
12
  - Gemfile.rails-3.0
13
+ - Gemfile.mongoid-4.0
11
14
  - Gemfile.mongoid-3.1
12
15
  - Gemfile.mongoid-3.0
13
16
  - Gemfile.mongoid-2.8
@@ -19,3 +22,25 @@ env:
19
22
  - DB=sqlite
20
23
  services:
21
24
  - mongodb
25
+ matrix:
26
+ exclude:
27
+ - rvm: 2.2
28
+ gemfile: Gemfile.rails-3.0
29
+ - rvm: 2.2
30
+ gemfile: Gemfile.rails-3.1
31
+ - rvm: 2.2
32
+ gemfile: Gemfile.rails-3.2
33
+ - rvm: 2.2
34
+ gemfile: Gemfile.mongoid-3.1
35
+ - rvm: 2.2
36
+ gemfile: Gemfile.mongoid-3.0
37
+ - rvm: 2.2
38
+ gemfile: Gemfile.mongoid-2.8
39
+ - rvm: 2.2
40
+ gemfile: Gemfile.mongoid-2.7
41
+ - rvm: 2.2
42
+ gemfile: Gemfile.mongoid-2.6
43
+ - rvm: 2.2
44
+ gemfile: Gemfile.mongoid-2.5
45
+ - rvm: 2.2
46
+ gemfile: Gemfile.mongoid-2.4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Next Release
2
2
 
3
+ ## 4.14.5
4
+
5
+ * Don't execute query when running `to_sql`
6
+ * Send backtrace to `uniform_notifier`
7
+ * Fix sse response check
8
+ * Dynamically delegate available notifiers to UniformNotifier
9
+
10
+ ## 4.14.4
11
+
12
+ * Fix false N + 1 warnings on Rails 4.2
13
+
14
+ ## 4.14.3
15
+
16
+ * Fix false positive on create
17
+
18
+ ## 4.14.2
19
+
20
+ * Hotfix nil object when `add_impossible_object`
21
+
22
+ ## 4.14.1
23
+
24
+ * Fix `has_one` then `has_many` associations in rails 4.2
25
+ * Append js and dom to html body in proper position
26
+
3
27
  ## 4.14.0 (10/03/2014)
4
28
 
5
29
  * Support rails 4.2
data/Gemfile.mongoid CHANGED
@@ -8,7 +8,5 @@ gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'mongoid', github: 'mongoid/mongoid'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
data/Gemfile.mongoid-2.4 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.2.16'
5
+ gem 'rails', '~> 3.2.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
- gem 'mongoid', '~> 2.4.12'
8
+ gem 'mongoid', '~> 2.4.0'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.mongoid-2.5 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.2.16'
5
+ gem 'rails', '~> 3.2.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
- gem 'mongoid', '~> 2.5.2'
8
+ gem 'mongoid', '~> 2.5.0'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.mongoid-2.6 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.2.16'
5
+ gem 'rails', '~> 3.2.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'mongoid', '~> 2.6.0'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.mongoid-2.7 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.2.16'
5
+ gem 'rails', '~> 3.2.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
- gem 'mongoid', '~> 2.7.1'
8
+ gem 'mongoid', '~> 2.7.0'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.mongoid-2.8 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.2'
5
+ gem 'rails', '~> 3.2.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
- gem 'mongoid', '~> 2.8'
8
+ gem 'mongoid', '~> 2.8.0'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.mongoid-3.0 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.2.16'
5
+ gem 'rails', '~> 3.2.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
- gem 'mongoid', '~> 3.0.23'
8
+ gem 'mongoid', '~> 3.0.0'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.mongoid-3.1 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.2.16'
5
+ gem 'rails', '~> 3.2.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
- gem 'mongoid', '~> 3.1.6'
8
+ gem 'mongoid', '~> 3.1.0'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.mongoid-4.0 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 4.0.5'
5
+ gem 'rails', '~> 4.0.0'
6
6
  gem 'sqlite3', platforms: [:ruby]
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'mongoid', '~> 4.0.0'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.rails-3.0 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.0.20'
5
+ 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
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.rails-3.1 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.1.12'
5
+ 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
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.rails-3.2 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 3.2.19'
5
+ 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
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.rails-4.0 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 4.0.9'
5
+ 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
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.rails-4.1 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 4.1.6'
5
+ gem 'rails', '~> 4.1.0'
6
6
  gem 'sqlite3'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/Gemfile.rails-4.2 CHANGED
@@ -2,14 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 4.2.0.beta2'
5
+ gem 'rails', '~> 4.2.0'
6
6
  gem 'sqlite3'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
9
9
 
10
10
  gem "rspec"
11
- gem "guard"
12
- gem "guard-rspec"
13
11
 
14
12
  gem 'coveralls', require: false
15
13
 
data/README.md CHANGED
@@ -55,8 +55,10 @@ config.after_initialize do
55
55
  Bullet.rails_logger = true
56
56
  Bullet.bugsnag = true
57
57
  Bullet.airbrake = true
58
+ Bullet.rollbar = true
58
59
  Bullet.add_footer = true
59
60
  Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
61
+ Bullet.slack = { webhook_url: 'http://some.slack.url', foo: 'bar' }
60
62
  end
61
63
  ```
62
64
 
@@ -67,13 +69,16 @@ The code above will enable all seven of the Bullet notification systems:
67
69
  * `Bullet.alert`: pop up a JavaScript alert in the browser
68
70
  * `Bullet.bullet_logger`: log to the Bullet log file (Rails.root/log/bullet.log)
69
71
  * `Bullet.rails_logger`: add warnings directly to the Rails log
72
+ * `Bullet.bugsnag`: add notifications to bugsnag
70
73
  * `Bullet.airbrake`: add notifications to airbrake
74
+ * `Bullet.rollbar`: add notifications to rollbar
71
75
  * `Bullet.console`: log warnings to your browser's console.log (Safari/Webkit browsers or Firefox w/Firebug installed)
72
76
  * `Bullet.growl`: pop up Growl warnings if your system has Growl installed. Requires a little bit of configuration
73
77
  * `Bullet.xmpp`: send XMPP/Jabber notifications to the receiver indicated. Note that the code will currently not handle the adding of contacts, so you will need to make both accounts indicated know each other manually before you will receive any notifications. If you restart the development server frequently, the 'coming online' sound for the Bullet account may start to annoy - in this case set :show_online_status to false; you will still get notifications, but the Bullet account won't announce it's online status anymore.
74
78
  * `Bullet.raise`: raise errors, useful for making your specs fail unless they have optimized queries
75
79
  * `Bullet.add_footer`: adds the details in the bottom left corner of the page
76
80
  * `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
81
+ * `Bullet.slack`: add notifications to slack
77
82
 
78
83
  Bullet also allows you to disable any of its detectors.
79
84
 
@@ -153,8 +158,9 @@ The Bullet gem uses rack middleware to profile requests. If you want to use Bull
153
158
  ```ruby
154
159
  Bullet.profile do
155
160
  # do anything
161
+
162
+ warnings = Bullet.warnings
156
163
  end
157
- warnings = Bullet.warnings
158
164
  ```
159
165
 
160
166
  ### Work with sinatra
@@ -429,4 +435,4 @@ Meanwhile, there's a line appended to `log/bullet.log`
429
435
  Post => [:comments]
430
436
  ```
431
437
 
432
- Copyright (c) 2009 - 2014 Richard Huang (flyerhzm@gmail.com), released under the MIT license
438
+ Copyright (c) 2009 - 2015 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.6.0"
21
+ s.add_runtime_dependency "uniform_notifier", "~> 1.9.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")
@@ -104,8 +104,10 @@ module Bullet
104
104
  alias_method :origin_reader, :reader
105
105
  def reader(force_reload = false)
106
106
  result = origin_reader(force_reload)
107
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
108
- Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
107
+ unless @inversed
108
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
109
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
110
+ end
109
111
  result
110
112
  end
111
113
  end
@@ -40,6 +40,7 @@ module Bullet
40
40
  # add includes in scope
41
41
  alias_method :origin_find_with_associations, :find_with_associations
42
42
  def find_with_associations
43
+ return origin_find_with_associations { |r| yield r } if block_given?
43
44
  records = origin_find_with_associations
44
45
  associations = (eager_load_values + includes_values).uniq
45
46
  records.each do |record|
@@ -106,8 +107,8 @@ module Bullet
106
107
  alias_method :origin_reader, :reader
107
108
  def reader(force_reload = false)
108
109
  result = origin_reader(force_reload)
109
- if @owner.class.name !~ /^HABTM_/
110
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
110
+ if @owner.class.name !~ /^HABTM_/ && !@inversed
111
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
111
112
  Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
112
113
  end
113
114
  result
@@ -2,6 +2,23 @@ module Bullet
2
2
  module ActiveRecord
3
3
  def self.enable
4
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 result.is_a? Array
11
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
12
+ Bullet::Detector::CounterCache.add_possible_objects(result)
13
+ elsif result.is_a? ::ActiveRecord::Base
14
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
15
+ Bullet::Detector::CounterCache.add_impossible_object(result)
16
+ end
17
+ result
18
+ end
19
+ end
20
+ end
21
+
5
22
  ::ActiveRecord::Relation.class_eval do
6
23
  alias_method :origin_to_a, :to_a
7
24
  # if select a collection of objects, then these objects have possible to cause N+1 query.
@@ -40,6 +57,7 @@ module Bullet
40
57
  # add includes in scope
41
58
  alias_method :origin_find_with_associations, :find_with_associations
42
59
  def find_with_associations
60
+ return origin_find_with_associations { |r| yield r } if block_given?
43
61
  records = origin_find_with_associations
44
62
  associations = (eager_load_values + includes_values).uniq
45
63
  records.each do |record|
@@ -117,10 +135,13 @@ module Bullet
117
135
  alias_method :origin_reader, :reader
118
136
  def reader(force_reload = false)
119
137
  result = origin_reader(force_reload)
120
- if @owner.class.name !~ /^HABTM_/
121
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless @inversed
138
+ if @owner.class.name !~ /^HABTM_/ && !@inversed
139
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
122
140
  Bullet::Detector::NPlusOneQuery.add_possible_objects(result)
123
141
  end
142
+ if ::ActiveRecord::Reflection::HasOneReflection === @reflection && result
143
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result)
144
+ end
124
145
  result
125
146
  end
126
147
  end
@@ -86,7 +86,10 @@ module Bullet
86
86
  value = object_associations[bullet_key]
87
87
  if value
88
88
  value.each do |v|
89
- result = v.is_a?(Hash) ? v.has_key?(associations) : v == associations
89
+ # associations == v comparision order is important here because
90
+ # v variable might be a squeel node where :== method is redefined,
91
+ # so it does not compare values at all and return unexpected results
92
+ result = v.is_a?(Hash) ? v.has_key?(associations) : associations == v
90
93
  return true if result
91
94
  end
92
95
  end
@@ -70,7 +70,7 @@ module Bullet
70
70
  end
71
71
 
72
72
  def associations_str
73
- ":include => #{@associations.map{ |a| a.to_s.to_sym unless a.is_a? Hash }.inspect}"
73
+ ":includes => #{@associations.map{ |a| a.to_s.to_sym unless a.is_a? Hash }.inspect}"
74
74
  end
75
75
  end
76
76
  end
@@ -15,6 +15,12 @@ module Bullet
15
15
  "N+1 Query #{@path ? "in #{@path}" : 'detected'}"
16
16
  end
17
17
 
18
+ def notification_data
19
+ super.merge(
20
+ :backtrace => @callers
21
+ )
22
+ end
23
+
18
24
  protected
19
25
  def call_stack_messages
20
26
  (['N+1 Query method call stack'] + @callers).join( "\n " )
data/lib/bullet/rack.rb CHANGED
@@ -10,17 +10,16 @@ module Bullet
10
10
  return @app.call(env) unless Bullet.enable?
11
11
  Bullet.start_request
12
12
  status, headers, response = @app.call(env)
13
- return [status, headers, response] if file?(headers) || sse?(response) || empty?(response)
13
+ return [status, headers, response] if file?(headers) || sse?(headers) || empty?(response)
14
14
 
15
15
  response_body = nil
16
16
  if Bullet.notification?
17
17
  if status == 200 && !response_body(response).frozen? && html_request?(headers, response)
18
- response_body = response_body(response) << Bullet.gather_inline_notifications
19
- add_footer_note(response_body) if Bullet.add_footer
18
+ response_body = response_body(response)
19
+ append_to_html_body(response_body, footer_note) if Bullet.add_footer
20
+ append_to_html_body(response_body, Bullet.gather_inline_notifications)
20
21
  headers['Content-Length'] = response_body.bytesize.to_s
21
22
  end
22
- end
23
- if Bullet.enable? && Bullet.notification?
24
23
  Bullet.perform_out_of_channel_notifications(env)
25
24
  end
26
25
  [status, headers, response_body ? [response_body] : response]
@@ -42,16 +41,25 @@ module Bullet
42
41
  end
43
42
  end
44
43
 
45
- def add_footer_note(response_body)
46
- response_body << "<div #{footer_div_attributes}>" + Bullet.footer_info.uniq.join("<br>") + "</div>"
44
+ def append_to_html_body(response_body, content)
45
+ if response_body.include?('</body>')
46
+ position = response_body.rindex('</body>')
47
+ response_body.insert(position, content)
48
+ else
49
+ response_body << content
50
+ end
51
+ end
52
+
53
+ def footer_note
54
+ "<div #{footer_div_attributes}>" + Bullet.footer_info.uniq.join("<br>") + "</div>"
47
55
  end
48
56
 
49
57
  def file?(headers)
50
58
  headers["Content-Transfer-Encoding"] == "binary"
51
59
  end
52
60
 
53
- def sse?(response)
54
- response.respond_to?(:stream) && response.stream.is_a?(ActionController::Live::Buffer)
61
+ def sse?(headers)
62
+ headers["Content-Type"] == "text/event-stream"
55
63
  end
56
64
 
57
65
  def html_request?(headers, response)
@@ -69,7 +77,7 @@ module Bullet
69
77
  private
70
78
  def footer_div_attributes
71
79
  <<EOF
72
- data-is-bullet-footer style="position: fixed; bottom: 0pt; left: 0pt; cursor: pointer; border-style: solid; border-color: rgb(153, 153, 153);
80
+ data-is-bullet-footer ondblclick="this.parentNode.removeChild(this);" style="position: fixed; bottom: 0pt; left: 0pt; cursor: pointer; border-style: solid; border-color: rgb(153, 153, 153);
73
81
  -moz-border-top-colors: none; -moz-border-right-colors: none; -moz-border-bottom-colors: none;
74
82
  -moz-border-left-colors: none; -moz-border-image: none; border-width: 2pt 2pt 0px 0px;
75
83
  padding: 5px; border-radius: 0pt 10pt 0pt 0px; background: none repeat scroll 0% 0% rgba(200, 200, 200, 0.8);
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Bullet
3
- VERSION = "4.14.0"
3
+ VERSION = "4.14.5"
4
4
  end
data/lib/bullet.rb CHANGED
@@ -29,7 +29,7 @@ module Bullet
29
29
  attr_reader :notification_collector, :whitelist
30
30
  attr_accessor :add_footer, :orm_pathches_applied
31
31
 
32
- delegate :alert=, :console=, :growl=, :rails_logger=, :xmpp=, :airbrake=, :bugsnag=, :to => UniformNotifier
32
+ delegate *UniformNotifier::AVAILABLE_NOTIFIERS.map { |notifier| "#{notifier}=" }, :to => UniformNotifier
33
33
 
34
34
  def raise=(should_raise)
35
35
  UniformNotifier.raise=(should_raise ? Notification::UnoptimizedQueryError : false)
@@ -160,7 +160,7 @@ module Bullet
160
160
 
161
161
  def footer_info
162
162
  info = []
163
- for_each_active_notifier_with_notification do |notification|
163
+ notification_collector.collection.each do |notification|
164
164
  info << notification.short_notice
165
165
  end
166
166
  info
@@ -176,14 +176,17 @@ module Bullet
176
176
  end
177
177
 
178
178
  def profile
179
- Bullet.start_request if Bullet.enable?
179
+ if Bullet.enable?
180
+ begin
181
+ Bullet.start_request
180
182
 
181
- yield
183
+ yield
182
184
 
183
- if Bullet.enable? && Bullet.notification?
184
- Bullet.perform_out_of_channel_notifications
185
+ Bullet.perform_out_of_channel_notifications if Bullet.notification?
186
+ ensure
187
+ Bullet.end_request
188
+ end
185
189
  end
186
- Bullet.end_request if Bullet.enable?
187
190
  end
188
191
 
189
192
  private
@@ -5,9 +5,9 @@ module Bullet
5
5
  describe NPlusOneQuery do
6
6
  subject { NPlusOneQuery.new([["caller1", "caller2"]], Post, [:comments, :votes], "path") }
7
7
 
8
- it { expect(subject.body_with_caller).to eq(" Post => [:comments, :votes]\n Add to your finder: :include => [:comments, :votes]\nN+1 Query method call stack\n caller1\n caller2\n") }
9
- it { expect([ subject.body_with_caller, subject.body_with_caller]).to eq([ " Post => [:comments, :votes]\n Add to your finder: :include => [:comments, :votes]\nN+1 Query method call stack\n caller1\n caller2\n", " Post => [:comments, :votes]\n Add to your finder: :include => [:comments, :votes]\nN+1 Query method call stack\n caller1\n caller2\n" ]) }
10
- it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Add to your finder: :include => [:comments, :votes]") }
8
+ it { expect(subject.body_with_caller).to eq(" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nN+1 Query method call stack\n caller1\n caller2\n") }
9
+ it { expect([subject.body_with_caller, subject.body_with_caller]).to eq([ " Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nN+1 Query method call stack\n caller1\n caller2\n", " Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]\nN+1 Query method call stack\n caller1\n caller2\n" ]) }
10
+ it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Add to your finder: :includes => [:comments, :votes]") }
11
11
  it { expect(subject.title).to eq("N+1 Query in path") }
12
12
  end
13
13
  end
@@ -5,7 +5,7 @@ module Bullet
5
5
  describe UnusedEagerLoading do
6
6
  subject { UnusedEagerLoading.new(Post, [:comments, :votes], "path") }
7
7
 
8
- it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Remove from your finder: :include => [:comments, :votes]") }
8
+ it { expect(subject.body).to eq(" Post => [:comments, :votes]\n Remove from your finder: :includes => [:comments, :votes]") }
9
9
  it { expect(subject.title).to eq("Unused Eager Loading in path") }
10
10
  end
11
11
  end
@@ -65,19 +65,19 @@ module Bullet
65
65
  end
66
66
 
67
67
  it "should change response body if notification is active" do
68
- expect(Bullet).to receive(:notification?).and_return(true).twice
68
+ expect(Bullet).to receive(:notification?).and_return(true)
69
69
  expect(Bullet).to receive(:gather_inline_notifications).and_return("<bullet></bullet>")
70
70
  expect(Bullet).to receive(:perform_out_of_channel_notifications)
71
71
  status, headers, response = middleware.call([200, {"Content-Type" => "text/html"}])
72
72
  expect(headers["Content-Length"]).to eq("56")
73
- expect(response).to eq(["<html><head></head><body></body></html><bullet></bullet>"])
73
+ expect(response).to eq(["<html><head></head><body><bullet></bullet></body></html>"])
74
74
  end
75
75
 
76
76
  it "should set the right Content-Length if response body contains accents" do
77
77
  response = Support::ResponseDouble.new
78
78
  response.body = "<html><head></head><body>é</body></html>"
79
79
  app.response = response
80
- expect(Bullet).to receive(:notification?).and_return(true).twice
80
+ expect(Bullet).to receive(:notification?).and_return(true)
81
81
  expect(Bullet).to receive(:gather_inline_notifications).and_return("<bullet></bullet>")
82
82
  status, headers, response = middleware.call([200, {"Content-Type" => "text/html"}])
83
83
  expect(headers["Content-Length"]).to eq("58")
@@ -219,6 +219,20 @@ if !mongoid? && active_record4?
219
219
 
220
220
  expect(Bullet::Detector::Association).to be_completely_preloading_associations
221
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
222
236
  end
223
237
 
224
238
  context "category => posts => writer" do
@@ -313,7 +327,7 @@ if !mongoid? && active_record4?
313
327
  expect(Bullet::Detector::Association).to be_completely_preloading_associations
314
328
  end
315
329
 
316
- it "should detect unused preload with comments => post" do
330
+ it "should detect unused preload with comment => post" do
317
331
  Comment.includes(:post).map(&:name)
318
332
  Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
319
333
  expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Comment, :post)
@@ -515,6 +529,17 @@ if !mongoid? && active_record4?
515
529
  end
516
530
  end
517
531
 
532
+ describe Bullet::Detector::Association, "has_one => has_many" do
533
+ it "should not detect preload association" do
534
+ user = User.first
535
+ user.submission.replies.map(&:name)
536
+ Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations
537
+ expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations
538
+
539
+ expect(Bullet::Detector::Association).to be_completely_preloading_associations
540
+ end
541
+ end
542
+
518
543
  describe Bullet::Detector::Association, "call one association that in possible objects" do
519
544
  it "should not detect preload association" do
520
545
  Post.all
@@ -2,6 +2,9 @@ class Category < ActiveRecord::Base
2
2
  has_many :posts, inverse_of: :category
3
3
  has_many :entries
4
4
 
5
- has_many :submissions
6
5
  has_many :users
6
+
7
+ def draft_post
8
+ posts.draft.first_or_create
9
+ end
7
10
  end
@@ -1,4 +1,6 @@
1
1
  class Comment < ActiveRecord::Base
2
2
  belongs_to :post, inverse_of: :comments
3
3
  belongs_to :author, class_name: "BaseUser"
4
+
5
+ validates :post, presence: true
4
6
  end
data/spec/models/post.rb CHANGED
@@ -1,10 +1,15 @@
1
1
  class Post < ActiveRecord::Base
2
- extend Bullet::Dependency
3
-
4
2
  belongs_to :category, inverse_of: :posts
5
3
  belongs_to :writer
6
4
  has_many :comments, inverse_of: :post
7
5
 
6
+ validates :category, presence: true
7
+
8
8
  scope :preload_comments, -> { includes(:comments) }
9
9
  scope :in_category_name, ->(name) { where(['categories.name = ?', name]).includes(:category) }
10
+ scope :draft, -> { where(active: false) }
11
+
12
+ def link=(*)
13
+ comments.new
14
+ end
10
15
  end
@@ -0,0 +1,3 @@
1
+ class Reply < ActiveRecord::Base
2
+ belongs_to :submission
3
+ end
@@ -1,4 +1,4 @@
1
1
  class Submission < ActiveRecord::Base
2
- belongs_to :category
3
2
  belongs_to :user
3
+ has_many :replies
4
4
  end
data/spec/spec_helper.rb CHANGED
@@ -56,11 +56,11 @@ if active_record?
56
56
  Support::SqliteSeed.seed_db
57
57
  end
58
58
 
59
- config.before(:each) do
59
+ config.before(:example) do
60
60
  Bullet.start_request
61
61
  end
62
62
 
63
- config.after(:each) do
63
+ config.after(:example) do
64
64
  Bullet.end_request
65
65
  end
66
66
  end
@@ -14,7 +14,7 @@ module Support
14
14
  category2 = Category.create(:name => 'second')
15
15
 
16
16
  post1 = category1.posts.create(:name => 'first', :writer => writer1)
17
- post1a = category1.posts.create(:name => 'like first', :writer => writer2)
17
+ post1a = category1.posts.create(:name => 'like first', :writer => writer2, active: false)
18
18
  post2 = category2.posts.create(:name => 'second', :writer => writer2)
19
19
 
20
20
  comment1 = post1.comments.create(:name => 'first', :author => writer1)
@@ -82,10 +82,13 @@ module Support
82
82
  user1 = User.create(:name => 'user1', :category => category1)
83
83
  user2 = User.create(:name => 'user2', :category => category1)
84
84
 
85
- submission1 = category1.submissions.create(:name => "submission1", :user => user1)
86
- submission2 = category1.submissions.create(:name => "submission2", :user => user2)
87
- submission3 = category2.submissions.create(:name => "submission3", :user => user1)
88
- submission4 = category2.submissions.create(:name => "submission4", :user => user2)
85
+ submission1 = user1.create_submission(:name => "submission1")
86
+ submission2 = user2.create_submission(:name => "submission2")
87
+
88
+ submission1.replies.create(:name => 'reply1')
89
+ submission1.replies.create(:name => 'reply2')
90
+ submission2.replies.create(:name => 'reply3')
91
+ submission2.replies.create(:name => 'reply4')
89
92
  end
90
93
 
91
94
  def setup_db
@@ -191,6 +194,7 @@ module Support
191
194
  t.column :name, :string
192
195
  t.column :category_id, :integer
193
196
  t.column :writer_id, :integer
197
+ t.column :active, :boolean, :default => true
194
198
  end
195
199
 
196
200
  create_table :relationships do |t|
@@ -211,9 +215,13 @@ module Support
211
215
  t.column :name, :string
212
216
  end
213
217
 
218
+ create_table :replies do |t|
219
+ t.column :name, :string
220
+ t.column :submission_id, :integer
221
+ end
222
+
214
223
  create_table :submissions do |t|
215
224
  t.column :name, :string
216
- t.column :category_id, :integer
217
225
  t.column :user_id, :integer
218
226
  end
219
227
 
data/update.sh ADDED
@@ -0,0 +1,14 @@
1
+ BUNDLE_GEMFILE=Gemfile.rails-4.2 bundle update
2
+ BUNDLE_GEMFILE=Gemfile.rails-4.1 bundle update
3
+ BUNDLE_GEMFILE=Gemfile.rails-4.0 bundle update
4
+ BUNDLE_GEMFILE=Gemfile.rails-3.2 bundle update
5
+ BUNDLE_GEMFILE=Gemfile.rails-3.1 bundle update
6
+ BUNDLE_GEMFILE=Gemfile.rails-3.0 bundle update
7
+ BUNDLE_GEMFILE=Gemfile.mongoid-4.0 bundle update
8
+ BUNDLE_GEMFILE=Gemfile.mongoid-3.1 bundle update
9
+ BUNDLE_GEMFILE=Gemfile.mongoid-3.0 bundle update
10
+ BUNDLE_GEMFILE=Gemfile.mongoid-2.8 bundle update
11
+ BUNDLE_GEMFILE=Gemfile.mongoid-2.7 bundle update
12
+ BUNDLE_GEMFILE=Gemfile.mongoid-2.6 bundle update
13
+ BUNDLE_GEMFILE=Gemfile.mongoid-2.5 bundle update
14
+ BUNDLE_GEMFILE=Gemfile.mongoid-2.4 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: 4.14.0
4
+ version: 4.14.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-03 00:00:00.000000000 Z
11
+ date: 2015-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: uniform_notifier
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.6.0
33
+ version: 1.9.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.6.0
40
+ version: 1.9.0
41
41
  description: help to kill N+1 queries and unused eager loading.
42
42
  email:
43
43
  - flyerhzm@gmail.com
@@ -150,6 +150,7 @@ files:
150
150
  - spec/models/pet.rb
151
151
  - spec/models/post.rb
152
152
  - spec/models/relationship.rb
153
+ - spec/models/reply.rb
153
154
  - spec/models/student.rb
154
155
  - spec/models/submission.rb
155
156
  - spec/models/teacher.rb
@@ -162,6 +163,7 @@ files:
162
163
  - spec/support/sqlite_seed.rb
163
164
  - tasks/bullet_tasks.rake
164
165
  - test.sh
166
+ - update.sh
165
167
  homepage: http://github.com/flyerhzm/bullet
166
168
  licenses:
167
169
  - MIT
@@ -182,7 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
182
184
  version: 1.3.6
183
185
  requirements: []
184
186
  rubyforge_project:
185
- rubygems_version: 2.2.2
187
+ rubygems_version: 2.4.5
186
188
  signing_key:
187
189
  specification_version: 4
188
190
  summary: help to kill N+1 queries and unused eager loading.
@@ -234,6 +236,7 @@ test_files:
234
236
  - spec/models/pet.rb
235
237
  - spec/models/post.rb
236
238
  - spec/models/relationship.rb
239
+ - spec/models/reply.rb
237
240
  - spec/models/student.rb
238
241
  - spec/models/submission.rb
239
242
  - spec/models/teacher.rb