From f1fc8e581b9f0f19aed3f1bb83555a974885fb2f Mon Sep 17 00:00:00 2001 From: satoru koyanagi Date: Wed, 22 Jul 2020 11:52:48 +0900 Subject: [PATCH 01/32] fix typo --- spec/bullet/detector/counter_cache_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/bullet/detector/counter_cache_spec.rb b/spec/bullet/detector/counter_cache_spec.rb index 454bba0f..138dc074 100644 --- a/spec/bullet/detector/counter_cache_spec.rb +++ b/spec/bullet/detector/counter_cache_spec.rb @@ -47,7 +47,7 @@ module Detector expect(CounterCache.conditions_met?(@post1, :associations)).to eq false end - it 'should be true when object is possible, and impossible' do + it 'should be false when object is possible, and impossible' do CounterCache.add_possible_objects(@post1) CounterCache.add_impossible_object(@post1) expect(CounterCache.conditions_met?(@post1, :associations)).to eq false From 3abac26cc088b58bb5b106a640d6a5ba92a71ac9 Mon Sep 17 00:00:00 2001 From: Nana Adjei Manu Date: Fri, 11 Sep 2020 05:08:30 +0000 Subject: [PATCH 02/32] Update Readme --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index ac394a1e..b75f8fe5 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,13 @@ or add it into a Gemfile (Bundler): gem 'bullet', group: 'development' ``` +enable the Bullet gem with generate command + +```ruby +bundle exec rails g bullet:install +``` +The generate command will auto generate the default configuration and may ask to include in the test environment as well. See below for custom configuration. + **Note**: make sure `bullet` gem is added after activerecord (rails) and mongoid. From 815caf25099e9a56efbd07cdf9d32eae4d3aaffd Mon Sep 17 00:00:00 2001 From: Matt Swanson Date: Wed, 30 Sep 2020 21:52:50 -0400 Subject: [PATCH 03/32] Update design of footer notification --- lib/bullet/rack.rb | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/lib/bullet/rack.rb b/lib/bullet/rack.rb index c683dbc2..37ee02af 100644 --- a/lib/bullet/rack.rb +++ b/lib/bullet/rack.rb @@ -15,9 +15,8 @@ def call(env) status, headers, response = @app.call(env) response_body = nil - if Bullet.notification? - if Bullet.inject_into_page? && !file?(headers) && !sse?(headers) && !empty?(response) && status == 200 + if !file?(headers) && !sse?(headers) && !empty?(response) && status == 200 if html_request?(headers, response) response_body = response_body(response) response_body = append_to_html_body(response_body, footer_note) if Bullet.add_footer @@ -55,14 +54,14 @@ def append_to_html_body(response_body, content) end def footer_note - "
" + footer_header + '
' + Bullet.footer_info.uniq.join('
') + '
' + "
Bullet Warnings
#{Bullet.footer_info.uniq.join('
')}#{footer_console_message}
" end def set_header(headers, header_name, header_array) # Many proxy applications such as Nginx and AWS ELB limit # the size a header to 8KB, so truncate the list of reports to # be under that limit - header_array.pop while header_array.to_json.length > 8 * 1_024 + header_array.pop while header_array.to_json.length > 8 * 1024 headers[header_name] = header_array.to_json end @@ -88,23 +87,28 @@ def response_body(response) private - def footer_div_attributes + def details_attributes + <<~EOF + id="bullet-footer" data-is-bullet-footer + style="cursor: pointer; position: fixed; left: 0px; bottom: 0px; z-index: 9999; background: #fdf2f2; color: #9b1c1c; font-size: 12px; border-radius: 0px 8px 0px 0px; border: 1px solid #9b1c1c;" + EOF + end + + def summary_attributes <<~EOF - id="bullet-footer" 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); - -moz-border-top-colors: none; -moz-border-right-colors: none; -moz-border-bottom-colors: none; - -moz-border-left-colors: none; -moz-border-image: none; border-width: 2pt 2pt 0px 0px; - padding: 3px 5px; border-radius: 0pt 10pt 0pt 0px; background: none repeat scroll 0% 0% rgba(200, 200, 200, 0.8); - color: rgb(119, 119, 119); font-size: 16px; font-family: 'Arial', sans-serif; z-index:9999;" + style="font-weight: 600; padding: 2px 8px" EOF end - def footer_header - cancel_button = - "×" + def footer_content_attributes + <<~EOF + style="padding: 8px; border-top: 1px solid #9b1c1c;" + EOF + end + + def footer_console_message if Bullet.console_enabled? - "See 'Uniform Notifier' in JS Console for Stacktrace#{cancel_button}" - else - cancel_button + "
See 'Uniform Notifier' in JS Console for Stacktrace" end end From b06680b61b5c37013baeadd6d577ec40fb433b39 Mon Sep 17 00:00:00 2001 From: Matt Swanson Date: Wed, 30 Sep 2020 21:58:32 -0400 Subject: [PATCH 04/32] Revert --- lib/bullet/rack.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/bullet/rack.rb b/lib/bullet/rack.rb index 37ee02af..95ac4be0 100644 --- a/lib/bullet/rack.rb +++ b/lib/bullet/rack.rb @@ -15,8 +15,9 @@ def call(env) status, headers, response = @app.call(env) response_body = nil + if Bullet.notification? - if !file?(headers) && !sse?(headers) && !empty?(response) && status == 200 + if Bullet.inject_into_page? && !file?(headers) && !sse?(headers) && !empty?(response) && status == 200 if html_request?(headers, response) response_body = response_body(response) response_body = append_to_html_body(response_body, footer_note) if Bullet.add_footer From 5f5224326ba7484f1d9cb9960186d474c6f0f79c Mon Sep 17 00:00:00 2001 From: Ryunosuke Sato Date: Tue, 3 Nov 2020 00:38:32 +0900 Subject: [PATCH 05/32] Fix to render bullet notification as html safe string In Rails 6, the spec of `ActiveSupport::SafeBuffer#insert` has been changed. Previously, it behaves like just String, but now `ActiveSupport::SafeBuffer` exactly. See for details: https://github.com/rails/rails/pull/33990 --- lib/bullet/rack.rb | 1 + spec/bullet/rack_spec.rb | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/lib/bullet/rack.rb b/lib/bullet/rack.rb index 95ac4be0..f74eec07 100644 --- a/lib/bullet/rack.rb +++ b/lib/bullet/rack.rb @@ -46,6 +46,7 @@ def empty?(response) def append_to_html_body(response_body, content) body = response_body.dup + content = content.html_safe if content.respond_to?(:html_safe) if body.include?('') position = body.rindex('') body.insert(position, content) diff --git a/spec/bullet/rack_spec.rb b/spec/bullet/rack_spec.rb index 7e8aaf48..47c1e52f 100644 --- a/spec/bullet/rack_spec.rb +++ b/spec/bullet/rack_spec.rb @@ -105,6 +105,18 @@ module Bullet expect(response.first).to include('<') end + it 'should change response body for html safe string if add_footer is true' do + expect(Bullet).to receive(:add_footer).twice.and_return(true) + app.response = Support::ResponseDouble.new.tap do |response| + response.body = ActiveSupport::SafeBuffer.new('') + end + _, headers, response = middleware.call('Content-Type' => 'text/html') + + expect(headers['Content-Length']).to eq((56 + middleware.send(:footer_note).length).to_s) + expect(response.first).to start_with('') + expect(response.first).to include('<') + end + it 'should change response body if console_enabled is true' do expect(Bullet).to receive(:console_enabled?).and_return(true) _, headers, response = middleware.call('Content-Type' => 'text/html') @@ -112,6 +124,16 @@ module Bullet expect(response).to eq(%w[]) end + it 'should change response body for html safe string if console_enabled is true' do + expect(Bullet).to receive(:console_enabled?).and_return(true) + app.response = Support::ResponseDouble.new.tap do |response| + response.body = ActiveSupport::SafeBuffer.new('') + end + _, headers, response = middleware.call('Content-Type' => 'text/html') + expect(headers['Content-Length']).to eq('56') + expect(response).to eq(%w[]) + end + it "shouldn't change response body unnecessarily" do expected_response = Support::ResponseDouble.new 'Actual body' app.response = expected_response From 1f0f0554b676589588936cdc824ca87937814a64 Mon Sep 17 00:00:00 2001 From: Rodolfo Carvalho Date: Tue, 3 Nov 2020 08:58:19 -0500 Subject: [PATCH 06/32] Removin arrow functions from bullet_xhr.js These add no benefit to the code and make it incompatible with IE <= 11. Using simple functions work just as well and make it work in a broader set of browsers. --- lib/bullet/bullet_xhr.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/bullet/bullet_xhr.js b/lib/bullet/bullet_xhr.js index 3199499f..bc74bd1e 100644 --- a/lib/bullet/bullet_xhr.js +++ b/lib/bullet/bullet_xhr.js @@ -30,7 +30,7 @@ ) { var bulletFooterText = this.getResponseHeader("X-bullet-footer-text"); if (bulletFooterText) { - setTimeout(() => { + setTimeout(function() { var oldHtml = document.querySelector("#bullet-footer").innerHTML.split("
"); var header = oldHtml[0]; oldHtml = oldHtml.slice(1, oldHtml.length); @@ -41,7 +41,7 @@ } var bulletConsoleText = this.getResponseHeader("X-bullet-console-text"); if (bulletConsoleText && typeof console !== "undefined" && console.log) { - setTimeout(() => { + setTimeout(function() { JSON.parse(bulletConsoleText).forEach((message) => { if (console.groupCollapsed && console.groupEnd) { console.groupCollapsed("Uniform Notifier"); From 62945b75197f468d5a5bcaf0080e4cb7c8decad9 Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Sat, 12 Dec 2020 11:35:04 +0800 Subject: [PATCH 07/32] Bumping version to 6.1.1 --- CHANGELOG.md | 5 +++++ Gemfile.rails-6.0 | 2 +- Gemfile.rails-6.1 | 15 +++++++++++++++ lib/bullet/version.rb | 2 +- 4 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 Gemfile.rails-6.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cee5b0d..bc0f9908 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## Next Release +## 6.1.1 (12/12/2020) + +* Add support Rails 6.1 +* Make whitelist thread safe + ## 6.1.0 (12/28/2019) * Add skip_html_injection flag diff --git a/Gemfile.rails-6.0 b/Gemfile.rails-6.0 index 8b3df2bb..428b948f 100644 --- a/Gemfile.rails-6.0 +++ b/Gemfile.rails-6.0 @@ -2,7 +2,7 @@ source "https://rubygems.org" gemspec -gem 'rails', '6.0.0' +gem 'rails', '~> 6.0.0' gem 'sqlite3' gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby] gem 'activerecord-import' diff --git a/Gemfile.rails-6.1 b/Gemfile.rails-6.1 new file mode 100644 index 00000000..9f231dbc --- /dev/null +++ b/Gemfile.rails-6.1 @@ -0,0 +1,15 @@ +source "https://rubygems.org" + +gemspec + +gem 'rails', '~> 6.1.0' +gem 'sqlite3' +gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby] +gem 'activerecord-import' + +gem "rspec" + +platforms :rbx do + gem 'rubysl', '~> 2.0' + gem 'rubinius-developer_tools' +end diff --git a/lib/bullet/version.rb b/lib/bullet/version.rb index 2b78a94f..8da7dd29 100644 --- a/lib/bullet/version.rb +++ b/lib/bullet/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Bullet - VERSION = '6.1.0' + VERSION = '6.1.1' end From 9c728cc282d5eb85ab6b76dfa8ee52ee3e5e599a Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Sat, 12 Dec 2020 13:42:34 +0800 Subject: [PATCH 08/32] Revert "make whitelist thread safe" This reverts commit 9cda9c224a46786ecfa894480c4dd4d304db2adb. --- lib/bullet.rb | 17 +++++++++-------- spec/bullet_spec.rb | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/bullet.rb b/lib/bullet.rb index 39afbc1a..ab932d70 100644 --- a/lib/bullet.rb +++ b/lib/bullet.rb @@ -38,6 +38,7 @@ class << self :stacktrace_includes, :stacktrace_excludes, :skip_html_injection + attr_reader :whitelist attr_accessor :add_footer, :orm_patches_applied available_notifiers = UniformNotifier::AVAILABLE_NOTIFIERS.map { |notifier| "#{notifier}=" } @@ -97,27 +98,27 @@ def stacktrace_excludes def add_whitelist(options) reset_whitelist - Thread.current[:whitelist][options[:type]][options[:class_name]] ||= [] - Thread.current[:whitelist][options[:type]][options[:class_name]] << options[:association].to_sym + @whitelist[options[:type]][options[:class_name]] ||= [] + @whitelist[options[:type]][options[:class_name]] << options[:association].to_sym end def delete_whitelist(options) reset_whitelist - Thread.current[:whitelist][options[:type]][options[:class_name]] ||= [] - Thread.current[:whitelist][options[:type]][options[:class_name]].delete(options[:association].to_sym) - Thread.current[:whitelist][options[:type]].delete_if { |_key, val| val.empty? } + @whitelist[options[:type]][options[:class_name]] ||= [] + @whitelist[options[:type]][options[:class_name]].delete(options[:association].to_sym) + @whitelist[options[:type]].delete_if { |_key, val| val.empty? } end def get_whitelist_associations(type, class_name) - Array(Thread.current[:whitelist][type][class_name]) + Array(@whitelist[type][class_name]) end def reset_whitelist - Thread.current[:whitelist] ||= { n_plus_one_query: {}, unused_eager_loading: {}, counter_cache: {} } + @whitelist ||= { n_plus_one_query: {}, unused_eager_loading: {}, counter_cache: {} } end def clear_whitelist - Thread.current[:whitelist] = nil + @whitelist = nil end def bullet_logger=(active) diff --git a/spec/bullet_spec.rb b/spec/bullet_spec.rb index ff252006..475ed4f8 100644 --- a/spec/bullet_spec.rb +++ b/spec/bullet_spec.rb @@ -88,7 +88,7 @@ it 'is deleted from the whitelist successfully' do Bullet.add_whitelist(type: :n_plus_one_query, class_name: 'Klass', association: :department) Bullet.delete_whitelist(type: :n_plus_one_query, class_name: 'Klass', association: :department) - expect(Thread.current[:whitelist][:n_plus_one_query]).to eq({}) + expect(Bullet.whitelist[:n_plus_one_query]).to eq({}) end end From c29ed32ad921c791ed7324bf093e9efbce68e0bb Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Sat, 12 Dec 2020 13:46:29 +0800 Subject: [PATCH 09/32] Bumping version to 6.1.2 --- CHANGELOG.md | 4 ++++ lib/bullet/version.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc0f9908..10946bdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Next Release +## 6.1.2 (12/12/2020) + +* Revert "Make whitelist thread safe" + ## 6.1.1 (12/12/2020) * Add support Rails 6.1 diff --git a/lib/bullet/version.rb b/lib/bullet/version.rb index 8da7dd29..d05d71c5 100644 --- a/lib/bullet/version.rb +++ b/lib/bullet/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Bullet - VERSION = '6.1.1' + VERSION = '6.1.2' end From 72206158e42afd2a969413aea40935aaee9a494a Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Tue, 15 Dec 2020 08:52:55 +0800 Subject: [PATCH 10/32] add xhr_script only when add_footer is enabled --- lib/bullet/rack.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bullet/rack.rb b/lib/bullet/rack.rb index f74eec07..1139bf35 100644 --- a/lib/bullet/rack.rb +++ b/lib/bullet/rack.rb @@ -22,7 +22,7 @@ def call(env) response_body = response_body(response) response_body = append_to_html_body(response_body, footer_note) if Bullet.add_footer response_body = append_to_html_body(response_body, Bullet.gather_inline_notifications) - response_body = append_to_html_body(response_body, xhr_script) + response_body = append_to_html_body(response_body, xhr_script) if Bullet.add_footer headers['Content-Length'] = response_body.bytesize.to_s else set_header(headers, 'X-bullet-footer-text', Bullet.footer_info.uniq) if Bullet.add_footer From 25b5c455153a18fae8a196ba3362b3805c319ce3 Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Thu, 17 Dec 2020 19:01:35 +0800 Subject: [PATCH 11/32] fix test failure --- spec/bullet/rack_spec.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/bullet/rack_spec.rb b/spec/bullet/rack_spec.rb index 47c1e52f..f12af10e 100644 --- a/spec/bullet/rack_spec.rb +++ b/spec/bullet/rack_spec.rb @@ -69,7 +69,6 @@ module Bullet expect(Bullet).to receive(:notification?).and_return(true) expect(Bullet).to receive(:console_enabled?).and_return(true) expect(Bullet).to receive(:gather_inline_notifications).and_return('') - expect(middleware).to receive(:xhr_script).and_return('') expect(Bullet).to receive(:perform_out_of_channel_notifications) _, headers, response = middleware.call('Content-Type' => 'text/html') expect(headers['Content-Length']).to eq('56') @@ -84,7 +83,7 @@ module Bullet allow(Bullet).to receive(:console_enabled?).and_return(true) expect(Bullet).to receive(:gather_inline_notifications).and_return('') _, headers, response = middleware.call('Content-Type' => 'text/html') - expect(headers['Content-Length']).to eq((58 + middleware.send(:xhr_script).length).to_s) + expect(headers['Content-Length']).to eq('58') end context 'with injection notifiers' do @@ -97,7 +96,7 @@ module Bullet end it 'should change response body if add_footer is true' do - expect(Bullet).to receive(:add_footer).twice.and_return(true) + expect(Bullet).to receive(:add_footer).exactly(3).times.and_return(true) _, headers, response = middleware.call('Content-Type' => 'text/html') expect(headers['Content-Length']).to eq((56 + middleware.send(:footer_note).length).to_s) @@ -106,7 +105,7 @@ module Bullet end it 'should change response body for html safe string if add_footer is true' do - expect(Bullet).to receive(:add_footer).twice.and_return(true) + expect(Bullet).to receive(:add_footer).exactly(3).times.and_return(true) app.response = Support::ResponseDouble.new.tap do |response| response.body = ActiveSupport::SafeBuffer.new('') end From 718312e55e1f8cf779ef457765bb952f0eb59eb6 Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Fri, 8 Jan 2021 08:38:20 +0800 Subject: [PATCH 12/32] fix warnings --- lib/bullet.rb | 10 ++++++---- lib/bullet/stack_trace_filter.rb | 3 +-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/bullet.rb b/lib/bullet.rb index ab932d70..8a95e5cc 100644 --- a/lib/bullet.rb +++ b/lib/bullet.rb @@ -41,7 +41,7 @@ class << self attr_reader :whitelist attr_accessor :add_footer, :orm_patches_applied - available_notifiers = UniformNotifier::AVAILABLE_NOTIFIERS.map { |notifier| "#{notifier}=" } + available_notifiers = UniformNotifier::AVAILABLE_NOTIFIERS.filter { |notifier| notifier != :raise }.map { |notifier| "#{notifier}=" } available_notifiers_options = { to: UniformNotifier } delegate(*available_notifiers, **available_notifiers_options) @@ -89,11 +89,11 @@ def counter_cache_enable? end def stacktrace_includes - @stacktrace_includes || [] + @stacktrace_includes ||= [] end def stacktrace_excludes - @stacktrace_excludes || [] + @stacktrace_excludes ||= [] end def add_whitelist(options) @@ -241,7 +241,9 @@ def console_enabled? end def inject_into_page? - !@skip_html_injection && (console_enabled? || add_footer) + return false if defined?(@skip_html_injection) && @skip_html_injection + + console_enabled? || add_footer end private diff --git a/lib/bullet/stack_trace_filter.rb b/lib/bullet/stack_trace_filter.rb index 209202b8..558e215d 100644 --- a/lib/bullet/stack_trace_filter.rb +++ b/lib/bullet/stack_trace_filter.rb @@ -59,8 +59,7 @@ def select_caller_locations end def ruby_19? - @ruby_19 = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') if @ruby_19.nil? - @ruby_19 + @ruby_19 ||= Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') end end end From 8f324432e4161614972c7f160745130dd16b0ea1 Mon Sep 17 00:00:00 2001 From: Awesome Code Date: Fri, 8 Jan 2021 00:39:47 +0000 Subject: [PATCH 13/32] Auto corrected by following Lint Ruby Performance/BlockGivenWithExplicitBlock --- lib/bullet/mongoid4x.rb | 2 +- lib/bullet/mongoid5x.rb | 2 +- lib/bullet/mongoid6x.rb | 2 +- lib/bullet/mongoid7x.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/bullet/mongoid4x.rb b/lib/bullet/mongoid4x.rb index f1a821ff..0fb62e5a 100644 --- a/lib/bullet/mongoid4x.rb +++ b/lib/bullet/mongoid4x.rb @@ -23,7 +23,7 @@ def last end def each(&block) - return to_enum unless block_given? + return to_enum unless block records = [] origin_each { |record| records << record } diff --git a/lib/bullet/mongoid5x.rb b/lib/bullet/mongoid5x.rb index f1a821ff..0fb62e5a 100644 --- a/lib/bullet/mongoid5x.rb +++ b/lib/bullet/mongoid5x.rb @@ -23,7 +23,7 @@ def last end def each(&block) - return to_enum unless block_given? + return to_enum unless block records = [] origin_each { |record| records << record } diff --git a/lib/bullet/mongoid6x.rb b/lib/bullet/mongoid6x.rb index 18265ce7..4fd92e77 100644 --- a/lib/bullet/mongoid6x.rb +++ b/lib/bullet/mongoid6x.rb @@ -23,7 +23,7 @@ def last(opt = {}) end def each(&block) - return to_enum unless block_given? + return to_enum unless block records = [] origin_each { |record| records << record } diff --git a/lib/bullet/mongoid7x.rb b/lib/bullet/mongoid7x.rb index b4070758..197dc954 100644 --- a/lib/bullet/mongoid7x.rb +++ b/lib/bullet/mongoid7x.rb @@ -23,7 +23,7 @@ def last(opts = {}) end def each(&block) - return to_enum unless block_given? + return to_enum unless block records = [] origin_each { |record| records << record } From 8f12b25d96556fcc47fac5a94ee46aec41e67e9d Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Fri, 8 Jan 2021 09:11:29 +0800 Subject: [PATCH 14/32] use Array#select rathe than Array#filter --- lib/bullet.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bullet.rb b/lib/bullet.rb index 8a95e5cc..0765805a 100644 --- a/lib/bullet.rb +++ b/lib/bullet.rb @@ -41,7 +41,7 @@ class << self attr_reader :whitelist attr_accessor :add_footer, :orm_patches_applied - available_notifiers = UniformNotifier::AVAILABLE_NOTIFIERS.filter { |notifier| notifier != :raise }.map { |notifier| "#{notifier}=" } + available_notifiers = UniformNotifier::AVAILABLE_NOTIFIERS.select { |notifier| notifier != :raise }.map { |notifier| "#{notifier}=" } available_notifiers_options = { to: UniformNotifier } delegate(*available_notifiers, **available_notifiers_options) From 9d16144c00ac2338ae22d4f5da1167aaa8b9dba5 Mon Sep 17 00:00:00 2001 From: kehra Date: Sat, 16 Jan 2021 17:31:52 +0900 Subject: [PATCH 15/32] add test for has_one with :through --- .../active_record/association_spec.rb | 36 +++++++++++++++++++ spec/models/attachment.rb | 5 +++ spec/models/submission.rb | 1 + spec/models/user.rb | 1 + spec/support/sqlite_seed.rb | 8 +++++ 5 files changed, 51 insertions(+) create mode 100644 spec/models/attachment.rb diff --git a/spec/integration/active_record/association_spec.rb b/spec/integration/active_record/association_spec.rb index 49b2186b..bede06b6 100644 --- a/spec/integration/active_record/association_spec.rb +++ b/spec/integration/active_record/association_spec.rb @@ -561,6 +561,42 @@ end end + describe Bullet::Detector::Association, 'has_one :through' do + context 'user => submission => attachment' do + it 'should detect non preload associations' do + User.all.each { |user| user.submission_attachment.file_name } + Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations + expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations + + expect(Bullet::Detector::Association).to be_detecting_unpreloaded_association_for(User, :submission_attachment) + end + + it 'should detect preload associations' do + User.includes(:submission_attachment).each { |user| user.submission_attachment.file_name } + Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations + expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations + + expect(Bullet::Detector::Association).to be_completely_preloading_associations + end + + it 'should not detect preload associations' do + User.all.map(&:name) + Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations + expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations + + expect(Bullet::Detector::Association).to be_completely_preloading_associations + end + + it 'should detect unused preload associations' do + User.includes(:submission_attachment).map(&:name) + Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations + expect(Bullet::Detector::Association).to be_unused_preload_associations_for(User, :submission_attachment) + + expect(Bullet::Detector::Association).to be_completely_preloading_associations + end + end + end + describe Bullet::Detector::Association, 'call one association that in possible objects' do it 'should not detect preload association' do Post.all diff --git a/spec/models/attachment.rb b/spec/models/attachment.rb new file mode 100644 index 00000000..ecd56a33 --- /dev/null +++ b/spec/models/attachment.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class Attachment < ActiveRecord::Base + belongs_to :submission +end diff --git a/spec/models/submission.rb b/spec/models/submission.rb index a4e3ec32..05889bf7 100644 --- a/spec/models/submission.rb +++ b/spec/models/submission.rb @@ -3,4 +3,5 @@ class Submission < ActiveRecord::Base belongs_to :user has_many :replies + has_one :attachment end diff --git a/spec/models/user.rb b/spec/models/user.rb index 94590640..17c8f4dc 100644 --- a/spec/models/user.rb +++ b/spec/models/user.rb @@ -2,5 +2,6 @@ class User < ActiveRecord::Base has_one :submission + has_one :submission_attachment, through: :submission, source: :attachment, class_name: 'Attachment' belongs_to :category end diff --git a/spec/support/sqlite_seed.rb b/spec/support/sqlite_seed.rb index 9a79947b..2d285bc0 100644 --- a/spec/support/sqlite_seed.rb +++ b/spec/support/sqlite_seed.rb @@ -95,6 +95,9 @@ def seed_db submission1.replies.create(name: 'reply2') submission2.replies.create(name: 'reply3') submission2.replies.create(name: 'reply4') + + submission1.create_attachment(file_name: 'submission1 file') + submission2.create_attachment(file_name: 'submission2 file') end def setup_db @@ -240,6 +243,11 @@ def setup_db t.column :name, :string t.column :category_id, :integer end + + create_table :attachments do |t| + t.column :file_name, :string + t.column :submission_id, :integer + end end end end From e06318360c5e288d5a0a8598459e1ca0cbeb7d0b Mon Sep 17 00:00:00 2001 From: kehra Date: Sat, 16 Jan 2021 17:36:20 +0900 Subject: [PATCH 16/32] consider ThroughAssociation at SingularAssociation like CollectionAssociation --- lib/bullet/active_record52.rb | 11 +++++++++++ lib/bullet/active_record60.rb | 11 +++++++++++ lib/bullet/active_record61.rb | 11 +++++++++++ spec/integration/active_record/association_spec.rb | 2 +- 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/bullet/active_record52.rb b/lib/bullet/active_record52.rb index 95c61315..a6c38fd2 100644 --- a/lib/bullet/active_record52.rb +++ b/lib/bullet/active_record52.rb @@ -202,6 +202,17 @@ def target if Bullet.start? if owner.class.name !~ /^HABTM_/ && !@inversed + if is_a? ::ActiveRecord::Associations::ThroughAssociation + Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name) + association = owner.association reflection.through_reflection.name + Array(association.target).each do |through_record| + Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name) + end + + if reflection.through_reflection != through_reflection + Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name) + end + end Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet::Detector::NPlusOneQuery.impossible?(owner) diff --git a/lib/bullet/active_record60.rb b/lib/bullet/active_record60.rb index d1edf616..45332b5d 100644 --- a/lib/bullet/active_record60.rb +++ b/lib/bullet/active_record60.rb @@ -229,6 +229,17 @@ def target if Bullet.start? if owner.class.name !~ /^HABTM_/ && !@inversed + if is_a? ::ActiveRecord::Associations::ThroughAssociation + Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name) + association = owner.association(reflection.through_reflection.name) + Array(association.target).each do |through_record| + Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name) + end + + if reflection.through_reflection != through_reflection + Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name) + end + end Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet::Detector::NPlusOneQuery.impossible?(owner) diff --git a/lib/bullet/active_record61.rb b/lib/bullet/active_record61.rb index e90d85cd..2e4712a3 100644 --- a/lib/bullet/active_record61.rb +++ b/lib/bullet/active_record61.rb @@ -229,6 +229,17 @@ def target if Bullet.start? if owner.class.name !~ /^HABTM_/ && !@inversed + if is_a? ::ActiveRecord::Associations::ThroughAssociation + Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name) + association = owner.association(reflection.through_reflection.name) + Array(association.target).each do |through_record| + Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name) + end + + if reflection.through_reflection != through_reflection + Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name) + end + end Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) if Bullet::Detector::NPlusOneQuery.impossible?(owner) diff --git a/spec/integration/active_record/association_spec.rb b/spec/integration/active_record/association_spec.rb index bede06b6..61746949 100644 --- a/spec/integration/active_record/association_spec.rb +++ b/spec/integration/active_record/association_spec.rb @@ -562,7 +562,7 @@ end describe Bullet::Detector::Association, 'has_one :through' do - context 'user => submission => attachment' do + context 'user => attachment' do it 'should detect non preload associations' do User.all.each { |user| user.submission_attachment.file_name } Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations From 8213b6991620bb754f74e822e7addabac863aad9 Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Thu, 21 Jan 2021 07:46:56 +0800 Subject: [PATCH 17/32] Bumping version to 6.1.3 --- CHANGELOG.md | 5 +++++ lib/bullet/version.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10946bdf..bcc8b1ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## Next Release +## 6.1.3 (01/21/2021) + +* Consider ThroughAssociation at SingularAssociation like CollectionAssociation +* Add xhr_script only when add_footer is enabled + ## 6.1.2 (12/12/2020) * Revert "Make whitelist thread safe" diff --git a/lib/bullet/version.rb b/lib/bullet/version.rb index d05d71c5..457e0c5f 100644 --- a/lib/bullet/version.rb +++ b/lib/bullet/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Bullet - VERSION = '6.1.2' + VERSION = '6.1.3' end From f8202e307b90e8fb128d60573b53d9e626c28a46 Mon Sep 17 00:00:00 2001 From: Sergei Smagin Date: Mon, 22 Feb 2021 11:27:05 +0300 Subject: [PATCH 18/32] Calculate Bullet.app_root and IS_RUBY_19(former ruby_19?) once Gem::Version.new and Gem::Version#<=> took more than half of all the execution time of Bullet::Detector::NPlusOneQuery.call_association, and Bullet.app_root roughly 1/5 more. None of this is changed without the app restart, so it's safe to calculate them once. --- lib/bullet.rb | 2 +- lib/bullet/stack_trace_filter.rb | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/bullet.rb b/lib/bullet.rb index 0765805a..00eff27f 100644 --- a/lib/bullet.rb +++ b/lib/bullet.rb @@ -73,7 +73,7 @@ def enable? end def app_root - (defined?(::Rails.root) ? Rails.root.to_s : Dir.pwd).to_s + @app_root ||= (defined?(::Rails.root) ? Rails.root.to_s : Dir.pwd).to_s end def n_plus_one_query_enable? diff --git a/lib/bullet/stack_trace_filter.rb b/lib/bullet/stack_trace_filter.rb index 558e215d..64611141 100644 --- a/lib/bullet/stack_trace_filter.rb +++ b/lib/bullet/stack_trace_filter.rb @@ -3,6 +3,7 @@ module Bullet module StackTraceFilter VENDOR_PATH = '/vendor' + IS_RUBY_19 = Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') def caller_in_project vendor_root = Bullet.app_root + VENDOR_PATH @@ -47,19 +48,15 @@ def pattern_matches?(location, pattern) end def location_as_path(location) - ruby_19? ? location : location.absolute_path.to_s + IS_RUBY_19 ? location : location.absolute_path.to_s end def select_caller_locations - if ruby_19? + if IS_RUBY_19 caller.select { |caller_path| yield caller_path } else caller_locations.select { |location| yield location } end end - - def ruby_19? - @ruby_19 ||= Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') - end end end From 91e62be34d5615e0166d4b7a59aeba2e295e937e Mon Sep 17 00:00:00 2001 From: Iain Beeston Date: Wed, 24 Feb 2021 11:10:47 +0000 Subject: [PATCH 19/32] Make readme clearer about what `skip_html_injection` The readme says that `skip_html_injection` prevents "XHR" from being injected into the page. That's not really what this option does - it prevents HTML from being injected (and also adds javascript to the page to intercept XHR requests). I've tweaked the wording so it's clearer that this isn't just about XHR. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b75f8fe5..bd7d356d 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ The code above will enable all of the Bullet notification systems: * `Bullet.rollbar`: add notifications to rollbar * `Bullet.sentry`: add notifications to sentry * `Bullet.add_footer`: adds the details in the bottom left corner of the page. Double click the footer or use close button to hide footer. -* `Bullet.skip_html_injection`: prevents Bullet from injecting XHR into the returned HTML. This must be false for receiving alerts or console logging. +* `Bullet.skip_html_injection`: prevents Bullet from injecting code into the returned HTML. This must be false for receiving alerts, showing the footer or console logging. * `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app * `Bullet.stacktrace_excludes`: ignore paths with any of these substrings in the stack trace, even if they are not in your main app. Each item can be a string (match substring), a regex, or an array where the first item is a path to match, and the second From bbaf1cff309b74d22e484c412588d28c43f7f572 Mon Sep 17 00:00:00 2001 From: Iain Beeston Date: Wed, 24 Feb 2021 12:14:46 +0000 Subject: [PATCH 20/32] Made specs check if/when the xhr script tag is added Before it was ambiguous because the output for the tag was empty. --- spec/bullet/rack_spec.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/spec/bullet/rack_spec.rb b/spec/bullet/rack_spec.rb index f12af10e..6d402ad9 100644 --- a/spec/bullet/rack_spec.rb +++ b/spec/bullet/rack_spec.rb @@ -90,7 +90,7 @@ module Bullet before do expect(Bullet).to receive(:notification?).and_return(true) allow(Bullet).to receive(:gather_inline_notifications).and_return('') - allow(middleware).to receive(:xhr_script).and_return('') + allow(middleware).to receive(:xhr_script).and_return('') allow(middleware).to receive(:footer_note).and_return('footer') expect(Bullet).to receive(:perform_out_of_channel_notifications) end @@ -99,9 +99,8 @@ module Bullet expect(Bullet).to receive(:add_footer).exactly(3).times.and_return(true) _, headers, response = middleware.call('Content-Type' => 'text/html') - expect(headers['Content-Length']).to eq((56 + middleware.send(:footer_note).length).to_s) - expect(response.first).to start_with('') - expect(response.first).to include('<') + expect(headers['Content-Length']).to eq((73 + middleware.send(:footer_note).length).to_s) + expect(response).to eq(%w[footer]) end it 'should change response body for html safe string if add_footer is true' do @@ -111,9 +110,8 @@ module Bullet end _, headers, response = middleware.call('Content-Type' => 'text/html') - expect(headers['Content-Length']).to eq((56 + middleware.send(:footer_note).length).to_s) - expect(response.first).to start_with('') - expect(response.first).to include('<') + expect(headers['Content-Length']).to eq((73 + middleware.send(:footer_note).length).to_s) + expect(response).to eq(%w[footer]) end it 'should change response body if console_enabled is true' do From ef00b6b38f0c3b62d2c436a113a154d689640ab1 Mon Sep 17 00:00:00 2001 From: Iain Beeston Date: Wed, 24 Feb 2021 14:46:25 +0000 Subject: [PATCH 21/32] Added an option to stop adding HTTP headers to API requests This also removes the custom javascript used to extract bullet info from the headers in ajax requests. --- CHANGELOG.md | 2 ++ README.md | 1 + lib/bullet.rb | 2 +- lib/bullet/rack.rb | 4 +-- spec/bullet/rack_spec.rb | 58 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcc8b1ac..81b68a88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## Next Release +* Added an option to stop adding HTTP headers to API requests + ## 6.1.3 (01/21/2021) * Consider ThroughAssociation at SingularAssociation like CollectionAssociation diff --git a/README.md b/README.md index bd7d356d..5eb728eb 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ The code above will enable all of the Bullet notification systems: * `Bullet.sentry`: add notifications to sentry * `Bullet.add_footer`: adds the details in the bottom left corner of the page. Double click the footer or use close button to hide footer. * `Bullet.skip_html_injection`: prevents Bullet from injecting code into the returned HTML. This must be false for receiving alerts, showing the footer or console logging. +* `Bullet.skip_http_headers`: don't add headers to API requests, and remove the javascript that relies on them. Note that this prevents bullet from logging warnings to the browser console or updating the footer. * `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app * `Bullet.stacktrace_excludes`: ignore paths with any of these substrings in the stack trace, even if they are not in your main app. Each item can be a string (match substring), a regex, or an array where the first item is a path to match, and the second diff --git a/lib/bullet.rb b/lib/bullet.rb index 00eff27f..15c6f63a 100644 --- a/lib/bullet.rb +++ b/lib/bullet.rb @@ -39,7 +39,7 @@ class << self :stacktrace_excludes, :skip_html_injection attr_reader :whitelist - attr_accessor :add_footer, :orm_patches_applied + attr_accessor :add_footer, :orm_patches_applied, :skip_http_headers available_notifiers = UniformNotifier::AVAILABLE_NOTIFIERS.select { |notifier| notifier != :raise }.map { |notifier| "#{notifier}=" } available_notifiers_options = { to: UniformNotifier } diff --git a/lib/bullet/rack.rb b/lib/bullet/rack.rb index 1139bf35..83f31cc3 100644 --- a/lib/bullet/rack.rb +++ b/lib/bullet/rack.rb @@ -22,9 +22,9 @@ def call(env) response_body = response_body(response) response_body = append_to_html_body(response_body, footer_note) if Bullet.add_footer response_body = append_to_html_body(response_body, Bullet.gather_inline_notifications) - response_body = append_to_html_body(response_body, xhr_script) if Bullet.add_footer + response_body = append_to_html_body(response_body, xhr_script) if Bullet.add_footer && !Bullet.skip_http_headers headers['Content-Length'] = response_body.bytesize.to_s - else + elsif !Bullet.skip_http_headers set_header(headers, 'X-bullet-footer-text', Bullet.footer_info.uniq) if Bullet.add_footer set_header(headers, 'X-bullet-console-text', Bullet.text_notifications) if Bullet.console_enabled? end diff --git a/spec/bullet/rack_spec.rb b/spec/bullet/rack_spec.rb index 6d402ad9..f04d0f37 100644 --- a/spec/bullet/rack_spec.rb +++ b/spec/bullet/rack_spec.rb @@ -114,6 +114,14 @@ module Bullet expect(response).to eq(%w[footer]) end + it 'should add the footer-text header for non-html requests when add_footer is true' do + allow(Bullet).to receive(:add_footer).at_least(:once).and_return(true) + allow(Bullet).to receive(:footer_info).and_return(['footer text']) + app.headers = {'Content-Type' => 'application/json'} + _, headers, _response = middleware.call({}) + expect(headers).to include('X-bullet-footer-text' => '["footer text"]') + end + it 'should change response body if console_enabled is true' do expect(Bullet).to receive(:console_enabled?).and_return(true) _, headers, response = middleware.call('Content-Type' => 'text/html') @@ -131,12 +139,62 @@ module Bullet expect(response).to eq(%w[]) end + it 'should add headers for non-html requests when console_enabled is true' do + allow(Bullet).to receive(:console_enabled?).at_least(:once).and_return(true) + allow(Bullet).to receive(:text_notifications).and_return(['text notifications']) + app.headers = {'Content-Type' => 'application/json'} + _, headers, _response = middleware.call({}) + expect(headers).to include('X-bullet-console-text' => '["text notifications"]') + end + it "shouldn't change response body unnecessarily" do expected_response = Support::ResponseDouble.new 'Actual body' app.response = expected_response _, _, response = middleware.call({}) expect(response).to eq(expected_response) end + + it "shouldn't add headers unnecessarily" do + app.headers = {'Content-Type' => 'application/json'} + _, headers, _response = middleware.call({}) + expect(headers).not_to include('X-bullet-footer-text') + expect(headers).not_to include('X-bullet-console-text') + end + + context "when skip_http_headers is enabled" do + before do + allow(Bullet).to receive(:skip_http_headers).and_return(true) + end + + it 'should include the footer but not the xhr script tag if add_footer is true' do + expect(Bullet).to receive(:add_footer).at_least(:once).and_return(true) + _, headers, response = middleware.call({}) + + expect(headers['Content-Length']).to eq((56 + middleware.send(:footer_note).length).to_s) + expect(response).to eq(%w[footer]) + end + + it 'should not include the xhr script tag if console_enabled is true' do + expect(Bullet).to receive(:console_enabled?).and_return(true) + _, headers, response = middleware.call({}) + expect(headers['Content-Length']).to eq('56') + expect(response).to eq(%w[]) + end + + it 'should not add the footer-text header for non-html requests when add_footer is true' do + allow(Bullet).to receive(:add_footer).at_least(:once).and_return(true) + app.headers = {'Content-Type' => 'application/json'} + _, headers, _response = middleware.call({}) + expect(headers).not_to include('X-bullet-footer-text') + end + + it 'should not add headers for non-html requests when console_enabled is true' do + allow(Bullet).to receive(:console_enabled?).at_least(:once).and_return(true) + app.headers = {'Content-Type' => 'application/json'} + _, headers, _response = middleware.call({}) + expect(headers).not_to include('X-bullet-console-text') + end + end end context 'when skip_html_injection is enabled' do From 417229210c5593d92e7693f69b83e9dad2cc6801 Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Fri, 26 Feb 2021 15:35:15 +0800 Subject: [PATCH 22/32] Bumping version to 6.1.4 --- CHANGELOG.md | 2 ++ lib/bullet/version.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81b68a88..54341c83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## Next Release +## 6.1.4 (02/26/2021) + * Added an option to stop adding HTTP headers to API requests ## 6.1.3 (01/21/2021) diff --git a/lib/bullet/version.rb b/lib/bullet/version.rb index 457e0c5f..984b2e15 100644 --- a/lib/bullet/version.rb +++ b/lib/bullet/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Bullet - VERSION = '6.1.3' + VERSION = '6.1.4' end From 218ab0717c3256ecc20f5d7e842f9528e2b6fb76 Mon Sep 17 00:00:00 2001 From: Milica Date: Fri, 26 Feb 2021 10:52:21 +0100 Subject: [PATCH 23/32] adding AppSignal to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5eb728eb..321cf0f1 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ config.after_initialize do Bullet.rails_logger = true Bullet.honeybadger = true Bullet.bugsnag = true + Bullet.appsignal = true Bullet.airbrake = true Bullet.rollbar = true Bullet.add_footer = true @@ -90,6 +91,7 @@ The code above will enable all of the Bullet notification systems: * `Bullet.honeybadger`: add notifications to Honeybadger * `Bullet.bugsnag`: add notifications to bugsnag * `Bullet.airbrake`: add notifications to airbrake +* `Bullet.appsignal`: add notifications to AppSignal * `Bullet.rollbar`: add notifications to rollbar * `Bullet.sentry`: add notifications to sentry * `Bullet.add_footer`: adds the details in the bottom left corner of the page. Double click the footer or use close button to hide footer. From 2c8a6d26f4a11bc8b3af5ff7da815401049732d4 Mon Sep 17 00:00:00 2001 From: Awesome Code Date: Sat, 27 Feb 2021 08:11:56 +0000 Subject: [PATCH 24/32] Auto corrected by following Format Ruby Code --- lib/bullet.rb | 3 ++- lib/bullet/active_record41.rb | 1 + lib/bullet/active_record42.rb | 1 + lib/bullet/detector/base.rb | 3 ++- lib/bullet/detector/n_plus_one_query.rb | 3 +-- lib/bullet/notification.rb | 3 ++- lib/bullet/rack.rb | 4 ++- lib/bullet/stack_trace_filter.rb | 5 ++-- perf/benchmark.rb | 5 +++- .../detector/unused_eager_loading_spec.rb | 8 ++++-- spec/bullet/rack_spec.rb | 26 ++++++++++--------- spec/models/folder.rb | 3 ++- spec/models/group.rb | 3 ++- spec/models/page.rb | 3 ++- spec/models/post.rb | 1 + spec/models/writer.rb | 3 ++- spec/spec_helper.rb | 2 -- spec/support/mongo_seed.rb | 1 + 18 files changed, 49 insertions(+), 29 deletions(-) diff --git a/lib/bullet.rb b/lib/bullet.rb index 15c6f63a..f333fbc5 100644 --- a/lib/bullet.rb +++ b/lib/bullet.rb @@ -41,7 +41,8 @@ class << self attr_reader :whitelist attr_accessor :add_footer, :orm_patches_applied, :skip_http_headers - available_notifiers = UniformNotifier::AVAILABLE_NOTIFIERS.select { |notifier| notifier != :raise }.map { |notifier| "#{notifier}=" } + available_notifiers = + UniformNotifier::AVAILABLE_NOTIFIERS.select { |notifier| notifier != :raise }.map { |notifier| "#{notifier}=" } available_notifiers_options = { to: UniformNotifier } delegate(*available_notifiers, **available_notifiers_options) diff --git a/lib/bullet/active_record41.rb b/lib/bullet/active_record41.rb index ec9e1bdc..74a263fa 100644 --- a/lib/bullet/active_record41.rb +++ b/lib/bullet/active_record41.rb @@ -30,6 +30,7 @@ def find_by_sql(sql, binds = []) ::ActiveRecord::Relation.class_eval do alias_method :origin_to_a, :to_a + # if select a collection of objects, then these objects have possible to cause N+1 query. # if select only one object, then the only one object has impossible to cause N+1 query. def to_a diff --git a/lib/bullet/active_record42.rb b/lib/bullet/active_record42.rb index 626d1d37..61afbda2 100644 --- a/lib/bullet/active_record42.rb +++ b/lib/bullet/active_record42.rb @@ -52,6 +52,7 @@ def _create_record_with_bullet(*args) ::ActiveRecord::Relation.class_eval do alias_method :origin_to_a, :to_a + # if select a collection of objects, then these objects have possible to cause N+1 query. # if select only one object, then the only one object has impossible to cause N+1 query. def to_a diff --git a/lib/bullet/detector/base.rb b/lib/bullet/detector/base.rb index 8f916ef2..0f458c59 100644 --- a/lib/bullet/detector/base.rb +++ b/lib/bullet/detector/base.rb @@ -2,6 +2,7 @@ module Bullet module Detector - class Base; end + class Base + end end end diff --git a/lib/bullet/detector/n_plus_one_query.rb b/lib/bullet/detector/n_plus_one_query.rb index acc8db43..38e01136 100644 --- a/lib/bullet/detector/n_plus_one_query.rb +++ b/lib/bullet/detector/n_plus_one_query.rb @@ -84,8 +84,7 @@ def association?(object, associations) # associations == v comparison order is important here because # v variable might be a squeel node where :== method is redefined, # so it does not compare values at all and return unexpected results - result = - v.is_a?(Hash) ? v.key?(associations) : associations == v + result = v.is_a?(Hash) ? v.key?(associations) : associations == v return true if result end diff --git a/lib/bullet/notification.rb b/lib/bullet/notification.rb index 909928db..9081c403 100644 --- a/lib/bullet/notification.rb +++ b/lib/bullet/notification.rb @@ -7,6 +7,7 @@ module Notification autoload :NPlusOneQuery, 'bullet/notification/n_plus_one_query' autoload :CounterCache, 'bullet/notification/counter_cache' - class UnoptimizedQueryError < StandardError; end + class UnoptimizedQueryError < StandardError + end end end diff --git a/lib/bullet/rack.rb b/lib/bullet/rack.rb index 83f31cc3..6dd59e69 100644 --- a/lib/bullet/rack.rb +++ b/lib/bullet/rack.rb @@ -22,7 +22,9 @@ def call(env) response_body = response_body(response) response_body = append_to_html_body(response_body, footer_note) if Bullet.add_footer response_body = append_to_html_body(response_body, Bullet.gather_inline_notifications) - response_body = append_to_html_body(response_body, xhr_script) if Bullet.add_footer && !Bullet.skip_http_headers + if Bullet.add_footer && !Bullet.skip_http_headers + response_body = append_to_html_body(response_body, xhr_script) + end headers['Content-Length'] = response_body.bytesize.to_s elsif !Bullet.skip_http_headers set_header(headers, 'X-bullet-footer-text', Bullet.footer_info.uniq) if Bullet.add_footer diff --git a/lib/bullet/stack_trace_filter.rb b/lib/bullet/stack_trace_filter.rb index 64611141..fa861db4 100644 --- a/lib/bullet/stack_trace_filter.rb +++ b/lib/bullet/stack_trace_filter.rb @@ -11,8 +11,9 @@ def caller_in_project select_caller_locations do |location| caller_path = location_as_path(location) caller_path.include?(Bullet.app_root) && !caller_path.include?(vendor_root) && - !caller_path.include?(bundler_path) || - Bullet.stacktrace_includes.any? { |include_pattern| pattern_matches?(location, include_pattern) } + !caller_path.include?(bundler_path) || Bullet.stacktrace_includes.any? { |include_pattern| + pattern_matches?(location, include_pattern) + } end end diff --git a/perf/benchmark.rb b/perf/benchmark.rb index d26a702a..da07b00c 100644 --- a/perf/benchmark.rb +++ b/perf/benchmark.rb @@ -30,7 +30,10 @@ class User < ActiveRecord::Base # create database bullet_benchmark; ActiveRecord::Base.establish_connection( - adapter: 'mysql2', database: 'bullet_benchmark', server: '/tmp/mysql.socket', username: 'root' + adapter: 'mysql2', + database: 'bullet_benchmark', + server: '/tmp/mysql.socket', + username: 'root' ) ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) } diff --git a/spec/bullet/detector/unused_eager_loading_spec.rb b/spec/bullet/detector/unused_eager_loading_spec.rb index ca2c58ef..4427b92f 100644 --- a/spec/bullet/detector/unused_eager_loading_spec.rb +++ b/spec/bullet/detector/unused_eager_loading_spec.rb @@ -19,7 +19,9 @@ module Detector it 'should get call associations if object and association are both in eager_loadings and call_object_associations' do UnusedEagerLoading.add_eager_loadings([@post], :association) UnusedEagerLoading.add_call_object_associations(@post, :association) - expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to eq([:association]) + expect(UnusedEagerLoading.send(:call_associations, @post.bullet_key, Set.new([:association]))).to eq( + [:association] + ) end it 'should not get call associations if not exist in call_object_associations' do @@ -30,7 +32,9 @@ module Detector context '.diff_object_associations' do it 'should return associations not exist in call_association' do - expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to eq([:association]) + expect(UnusedEagerLoading.send(:diff_object_associations, @post.bullet_key, Set.new([:association]))).to eq( + [:association] + ) end it 'should return empty if associations exist in call_association' do diff --git a/spec/bullet/rack_spec.rb b/spec/bullet/rack_spec.rb index f04d0f37..b9e882d7 100644 --- a/spec/bullet/rack_spec.rb +++ b/spec/bullet/rack_spec.rb @@ -105,9 +105,10 @@ module Bullet it 'should change response body for html safe string if add_footer is true' do expect(Bullet).to receive(:add_footer).exactly(3).times.and_return(true) - app.response = Support::ResponseDouble.new.tap do |response| - response.body = ActiveSupport::SafeBuffer.new('') - end + app.response = + Support::ResponseDouble.new.tap do |response| + response.body = ActiveSupport::SafeBuffer.new('') + end _, headers, response = middleware.call('Content-Type' => 'text/html') expect(headers['Content-Length']).to eq((73 + middleware.send(:footer_note).length).to_s) @@ -117,7 +118,7 @@ module Bullet it 'should add the footer-text header for non-html requests when add_footer is true' do allow(Bullet).to receive(:add_footer).at_least(:once).and_return(true) allow(Bullet).to receive(:footer_info).and_return(['footer text']) - app.headers = {'Content-Type' => 'application/json'} + app.headers = { 'Content-Type' => 'application/json' } _, headers, _response = middleware.call({}) expect(headers).to include('X-bullet-footer-text' => '["footer text"]') end @@ -131,9 +132,10 @@ module Bullet it 'should change response body for html safe string if console_enabled is true' do expect(Bullet).to receive(:console_enabled?).and_return(true) - app.response = Support::ResponseDouble.new.tap do |response| - response.body = ActiveSupport::SafeBuffer.new('') - end + app.response = + Support::ResponseDouble.new.tap do |response| + response.body = ActiveSupport::SafeBuffer.new('') + end _, headers, response = middleware.call('Content-Type' => 'text/html') expect(headers['Content-Length']).to eq('56') expect(response).to eq(%w[]) @@ -142,7 +144,7 @@ module Bullet it 'should add headers for non-html requests when console_enabled is true' do allow(Bullet).to receive(:console_enabled?).at_least(:once).and_return(true) allow(Bullet).to receive(:text_notifications).and_return(['text notifications']) - app.headers = {'Content-Type' => 'application/json'} + app.headers = { 'Content-Type' => 'application/json' } _, headers, _response = middleware.call({}) expect(headers).to include('X-bullet-console-text' => '["text notifications"]') end @@ -155,13 +157,13 @@ module Bullet end it "shouldn't add headers unnecessarily" do - app.headers = {'Content-Type' => 'application/json'} + app.headers = { 'Content-Type' => 'application/json' } _, headers, _response = middleware.call({}) expect(headers).not_to include('X-bullet-footer-text') expect(headers).not_to include('X-bullet-console-text') end - context "when skip_http_headers is enabled" do + context 'when skip_http_headers is enabled' do before do allow(Bullet).to receive(:skip_http_headers).and_return(true) end @@ -183,14 +185,14 @@ module Bullet it 'should not add the footer-text header for non-html requests when add_footer is true' do allow(Bullet).to receive(:add_footer).at_least(:once).and_return(true) - app.headers = {'Content-Type' => 'application/json'} + app.headers = { 'Content-Type' => 'application/json' } _, headers, _response = middleware.call({}) expect(headers).not_to include('X-bullet-footer-text') end it 'should not add headers for non-html requests when console_enabled is true' do allow(Bullet).to receive(:console_enabled?).at_least(:once).and_return(true) - app.headers = {'Content-Type' => 'application/json'} + app.headers = { 'Content-Type' => 'application/json' } _, headers, _response = middleware.call({}) expect(headers).not_to include('X-bullet-console-text') end diff --git a/spec/models/folder.rb b/spec/models/folder.rb index 8bccd844..a7af71e8 100644 --- a/spec/models/folder.rb +++ b/spec/models/folder.rb @@ -1,3 +1,4 @@ # frozen_string_literal: true -class Folder < Document; end +class Folder < Document +end diff --git a/spec/models/group.rb b/spec/models/group.rb index c687f506..0331c1fb 100644 --- a/spec/models/group.rb +++ b/spec/models/group.rb @@ -1,3 +1,4 @@ # frozen_string_literal: true -class Group < ActiveRecord::Base; end +class Group < ActiveRecord::Base +end diff --git a/spec/models/page.rb b/spec/models/page.rb index eeae5cc6..a7faf62a 100644 --- a/spec/models/page.rb +++ b/spec/models/page.rb @@ -1,3 +1,4 @@ # frozen_string_literal: true -class Page < Document; end +class Page < Document +end diff --git a/spec/models/post.rb b/spec/models/post.rb index 45a56be1..741c8f7e 100644 --- a/spec/models/post.rb +++ b/spec/models/post.rb @@ -21,6 +21,7 @@ def link=(*) next unless trigger_after_save temp_comment = Comment.new(post: self) + # this triggers self to be "possible", even though it's # not saved yet temp_comment.post diff --git a/spec/models/writer.rb b/spec/models/writer.rb index 5c995dfb..b7eacf56 100644 --- a/spec/models/writer.rb +++ b/spec/models/writer.rb @@ -1,3 +1,4 @@ # frozen_string_literal: true -class Writer < BaseUser; end +class Writer < BaseUser +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 92951f58..ab79eaae 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,12 +4,10 @@ begin require 'active_record' rescue LoadError - end begin require 'mongoid' rescue LoadError - end module Rails diff --git a/spec/support/mongo_seed.rb b/spec/support/mongo_seed.rb index b137f0ed..9374b696 100644 --- a/spec/support/mongo_seed.rb +++ b/spec/support/mongo_seed.rb @@ -45,6 +45,7 @@ def setup_db Mongoid.configure do |config| config.load_configuration(clients: { default: { database: 'bullet', hosts: %w[localhost:27017] } }) end + # Increase the level from DEBUG in order to avoid excessive logging to the screen Mongo::Logger.logger.level = Logger::WARN end From 05bf225ed4de79f87445ff4ac20c19c9b3ab57a2 Mon Sep 17 00:00:00 2001 From: Awesome Code Date: Sat, 27 Feb 2021 08:13:17 +0000 Subject: [PATCH 25/32] Auto corrected by following Lint Ruby Lint/DeprecatedConstants --- lib/bullet.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bullet.rb b/lib/bullet.rb index f333fbc5..f95282b0 100644 --- a/lib/bullet.rb +++ b/lib/bullet.rb @@ -133,7 +133,7 @@ def bullet_logger=(active) end def debug(title, message) - puts "[Bullet][#{title}] #{message}" if ENV[BULLET_DEBUG] == TRUE + puts "[Bullet][#{title}] #{message}" if ENV[BULLET_DEBUG] == true end def start_request From 06f0d304cbb3b3f52d2dabb2574eb2e98f3b1ac9 Mon Sep 17 00:00:00 2001 From: Richard Huang Date: Sat, 27 Feb 2021 18:01:34 +0800 Subject: [PATCH 26/32] remove const BULLET_DEBUG and TRUE --- lib/bullet.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/bullet.rb b/lib/bullet.rb index f95282b0..d900d349 100644 --- a/lib/bullet.rb +++ b/lib/bullet.rb @@ -20,9 +20,6 @@ module Bullet autoload :Registry, 'bullet/registry' autoload :NotificationCollector, 'bullet/notification_collector' - BULLET_DEBUG = 'BULLET_DEBUG' - TRUE = 'true' - if defined?(Rails::Railtie) class BulletRailtie < Rails::Railtie initializer 'bullet.configure_rails_initialization' do |app| @@ -133,7 +130,7 @@ def bullet_logger=(active) end def debug(title, message) - puts "[Bullet][#{title}] #{message}" if ENV[BULLET_DEBUG] == true + puts "[Bullet][#{title}] #{message}" if ENV['BULLET_DEBUG'] == 'true' end def start_request From c574557837a6a0edd0994de5b36b9d6857783976 Mon Sep 17 00:00:00 2001 From: Taher Ahmed Ghaleb Date: Mon, 8 Mar 2021 23:56:00 -0500 Subject: [PATCH 27/32] Enable bundler caching for travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 48b0092e..8fae77d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ matrix: gemfile: Gemfile.rails-4.0 env: - DB=sqlite +cache: bundler before_install: - "find /home/travis/.rvm/rubies -wholename '*default/bundler-*.gemspec' -delete" - gem install bundler -v '< 2' From eb08f491c9931d04c900d36baf17bc4707b1f3a3 Mon Sep 17 00:00:00 2001 From: Rafael Gibim <9031589+Drowze@users.noreply.github.com> Date: Tue, 4 May 2021 15:55:27 +0100 Subject: [PATCH 28/32] Do not use `Rails.root` if it's nil Some gems might add `Railtie` dependency (Railtie defines `Rails.root` as `nil` if `Rails.application` is nil) --- lib/bullet.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/bullet.rb b/lib/bullet.rb index d900d349..d7151af6 100644 --- a/lib/bullet.rb +++ b/lib/bullet.rb @@ -70,8 +70,9 @@ def enable? !!@enable end + # Rails.root might be nil if `railties` is a dependency on a project that does not use Rails def app_root - @app_root ||= (defined?(::Rails.root) ? Rails.root.to_s : Dir.pwd).to_s + @app_root ||= (defined?(::Rails.root) && !::Rails.root.nil? ? Rails.root.to_s : Dir.pwd).to_s end def n_plus_one_query_enable? From 8031837ca391a47f800da7f944f11b0625b14f1b Mon Sep 17 00:00:00 2001 From: Luka Huang Date: Thu, 6 May 2021 19:00:53 +0800 Subject: [PATCH 29/32] Fix typo in tests --- spec/bullet/ext/object_spec.rb | 2 +- spec/integration/active_record/association_spec.rb | 4 ++-- spec/integration/mongoid/association_spec.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/bullet/ext/object_spec.rb b/spec/bullet/ext/object_spec.rb index f352843c..ec3d9317 100644 --- a/spec/bullet/ext/object_spec.rb +++ b/spec/bullet/ext/object_spec.rb @@ -10,7 +10,7 @@ end if mongoid? - it 'should return class with namesapce and id composition' do + it 'should return class with namespace and id composition' do post = Mongoid::Post.first expect(post.bullet_key).to eq("Mongoid::Post:#{post.id}") end diff --git a/spec/integration/active_record/association_spec.rb b/spec/integration/active_record/association_spec.rb index 61746949..f03ea938 100644 --- a/spec/integration/active_record/association_spec.rb +++ b/spec/integration/active_record/association_spec.rb @@ -129,7 +129,7 @@ expect(Bullet::Detector::Association).to be_completely_preloading_associations end - it 'should detect unused preload with post => commnets, no category => posts' do + it 'should detect unused preload with post => comments, no category => posts' do Category.includes(posts: :comments).each { |category| category.posts.map(&:name) } Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations expect(Bullet::Detector::Association).to be_unused_preload_associations_for(Post, :comments) @@ -202,7 +202,7 @@ expect(Bullet::Detector::Association).to be_completely_preloading_associations end - it 'should detect preload with post => commnets' do + it 'should detect preload with post => comments' do Post.first.comments.map(&:name) Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations diff --git a/spec/integration/mongoid/association_spec.rb b/spec/integration/mongoid/association_spec.rb index 09a4bb6a..35b7ce1e 100644 --- a/spec/integration/mongoid/association_spec.rb +++ b/spec/integration/mongoid/association_spec.rb @@ -118,7 +118,7 @@ expect(Bullet::Detector::Association).to be_completely_preloading_associations end - it 'should detect preload with post => commnets' do + it 'should detect preload with post => comments' do Mongoid::Post.first.comments.map(&:name) Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations From 4cbd426261feb0bb5938adf0107d7aee6b44482d Mon Sep 17 00:00:00 2001 From: kei-p Date: Fri, 7 May 2021 17:23:14 +0900 Subject: [PATCH 30/32] Fix onload called twice --- lib/bullet/bullet_xhr.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/bullet/bullet_xhr.js b/lib/bullet/bullet_xhr.js index bc74bd1e..ee91c5a3 100644 --- a/lib/bullet/bullet_xhr.js +++ b/lib/bullet/bullet_xhr.js @@ -20,6 +20,7 @@ if (this.onload) { this._storedOnload = this.onload; } + this.onload = null this.addEventListener("load", bulletXHROnload); return Reflect.apply(oldSend, this, arguments); } From d0288e6d02aec569a467e3159a7be6cef506075d Mon Sep 17 00:00:00 2001 From: Simon Dawson Date: Thu, 10 Jun 2021 10:03:18 +0100 Subject: [PATCH 31/32] Support Rack::Files::Iterator responses When using the Rack::Static middleware, the response will be a Rack::Files::Iterator. Such a response will break `Bullet::Rack#response_body`, with the result that non-HTML files will not be served correctly. Seen when trying to use the Sidekiq admin engine in a Rails application that also uses Bullet. --- lib/bullet/rack.rb | 2 +- spec/bullet/rack_spec.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/bullet/rack.rb b/lib/bullet/rack.rb index 6dd59e69..9bff0e52 100644 --- a/lib/bullet/rack.rb +++ b/lib/bullet/rack.rb @@ -84,7 +84,7 @@ def html_request?(headers, response) def response_body(response) if response.respond_to?(:body) Array === response.body ? response.body.first : response.body - else + elsif response.respond_to?(:first) response.first end end diff --git a/spec/bullet/rack_spec.rb b/spec/bullet/rack_spec.rb index b9e882d7..7f19b44a 100644 --- a/spec/bullet/rack_spec.rb +++ b/spec/bullet/rack_spec.rb @@ -2,6 +2,8 @@ require 'spec_helper' +require 'rack/files' + module Bullet describe Rack do let(:middleware) { Bullet::Rack.new app } @@ -261,6 +263,15 @@ module Bullet expect(middleware.response_body(response)).to eq body_string end end + + context 'when `response` is a Rack::Files::Iterator' do + let(:response) { instance_double(::Rack::Files::Iterator) } + before { allow(response).to receive(:is_a?).with(::Rack::Files::Iterator) { true } } + + it 'should return nil' do + expect(middleware.response_body(response)).to be_nil + end + end end end end From 660a05afc93ad50c55c825d4f8217ce639c03021 Mon Sep 17 00:00:00 2001 From: Trevor Broaddus Date: Mon, 14 Jun 2021 12:32:56 -0500 Subject: [PATCH 32/32] Bug: Ensure HABTM associations are not incorrectly labeled n+1 Prior to this commit, unless your HABTM join table excluded the `id` primary key column, it would be erroneously marked as a potential n+1 query. Other HABTM queries that had join tables _without_ an `id` column were properly ignored. This exclusion _seems_ to be a side-effect of excluding objects that don't have primary keys/id columns in an effort to ignore non-persisted objects (stemming from [this commit](https://github.com/flyerhzm/bullet/blob/2c8a6d26f4a11bc8b3af5ff7da815401049732d4/lib/bullet/detector/n_plus_one_query.rb#L37)). This commit, instead, explicitly ignores HABTM models when checking for potential objects that could have a n+1 impact since they are join tables that typically aren't queried for specifically but instead are joined on. --- lib/bullet/detector/n_plus_one_query.rb | 1 + lib/bullet/stack_trace_filter.rb | 1 + spec/integration/active_record/association_spec.rb | 9 +++++++++ spec/models/deal.rb | 5 +++++ spec/models/post.rb | 1 + spec/support/sqlite_seed.rb | 12 ++++++++++++ test.sh | 1 + 7 files changed, 30 insertions(+) create mode 100644 spec/models/deal.rb diff --git a/lib/bullet/detector/n_plus_one_query.rb b/lib/bullet/detector/n_plus_one_query.rb index 38e01136..adce09d7 100644 --- a/lib/bullet/detector/n_plus_one_query.rb +++ b/lib/bullet/detector/n_plus_one_query.rb @@ -35,6 +35,7 @@ def add_possible_objects(object_or_objects) objects = Array(object_or_objects) return if objects.map(&:bullet_primary_key_value).compact.empty? + return if objects.all? { |obj| obj.class.name =~ /^HABTM_/ } Bullet.debug( 'Detector::NPlusOneQuery#add_possible_objects', diff --git a/lib/bullet/stack_trace_filter.rb b/lib/bullet/stack_trace_filter.rb index fa861db4..d652fd11 100644 --- a/lib/bullet/stack_trace_filter.rb +++ b/lib/bullet/stack_trace_filter.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true +require "bundler" module Bullet module StackTraceFilter diff --git a/spec/integration/active_record/association_spec.rb b/spec/integration/active_record/association_spec.rb index f03ea938..04fa0a3f 100644 --- a/spec/integration/active_record/association_spec.rb +++ b/spec/integration/active_record/association_spec.rb @@ -401,6 +401,15 @@ end describe Bullet::Detector::Association, 'has_and_belongs_to_many' do + context 'posts <=> deals' do + it 'should detect preload associations with join tables that have identifier' do + Post.includes(:deals).each { |post| post.deals.map(&:name) } + Bullet::Detector::UnusedEagerLoading.check_unused_preload_associations + expect(Bullet::Detector::Association).not_to be_has_unused_preload_associations + + expect(Bullet::Detector::Association).to be_completely_preloading_associations + end + end context 'students <=> teachers' do it 'should detect non preload associations' do Student.all.each { |student| student.teachers.map(&:name) } diff --git a/spec/models/deal.rb b/spec/models/deal.rb new file mode 100644 index 00000000..94b0fe57 --- /dev/null +++ b/spec/models/deal.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class Deal < ActiveRecord::Base + has_and_belongs_to_many :posts +end diff --git a/spec/models/post.rb b/spec/models/post.rb index 741c8f7e..31168c08 100644 --- a/spec/models/post.rb +++ b/spec/models/post.rb @@ -4,6 +4,7 @@ class Post < ActiveRecord::Base belongs_to :category, inverse_of: :posts belongs_to :writer has_many :comments, inverse_of: :post + has_and_belongs_to_many :deals validates :category, presence: true diff --git a/spec/support/sqlite_seed.rb b/spec/support/sqlite_seed.rb index 2d285bc0..92550236 100644 --- a/spec/support/sqlite_seed.rb +++ b/spec/support/sqlite_seed.rb @@ -21,6 +21,13 @@ def seed_db post2 = category2.posts.create(name: 'second', writer: writer2) post3 = category2.posts.create(name: 'third', writer: writer2) + deal1 = Deal.new(name: 'Deal 1') + deal1.posts << post1 + deal1.posts << post2 + deal2 = Deal.new(name: 'Deal 2') + post1.deals << deal1 + post1.deals << deal2 + comment1 = post1.comments.create(name: 'first', author: writer1) comment2 = post1.comments.create(name: 'first2', author: writer1) comment3 = post1.comments.create(name: 'first3', author: writer1) @@ -156,6 +163,11 @@ def setup_db t.column :hotel_id, :integer end + create_table :deals_posts do |t| + t.column :deal_id, :integer + t.column :post_id, :integer + end + create_table :documents do |t| t.string :name t.string :type diff --git a/test.sh b/test.sh index e2299461..7c31a68e 100755 --- a/test.sh +++ b/test.sh @@ -1,5 +1,6 @@ #bundle update rails && bundle exec rspec spec #BUNDLE_GEMFILE=Gemfile.mongoid bundle update mongoid && BUNDLE_GEMFILE=Gemfile.mongoid bundle exec rspec spec +BUNDLE_GEMFILE=Gemfile.rails-6.1 bundle && BUNDLE_GEMFILE=Gemfile.rails-6.1 bundle exec rspec spec BUNDLE_GEMFILE=Gemfile.rails-6.0 bundle && BUNDLE_GEMFILE=Gemfile.rails-6.0 bundle exec rspec spec BUNDLE_GEMFILE=Gemfile.rails-5.2 bundle && BUNDLE_GEMFILE=Gemfile.rails-5.2 bundle exec rspec spec BUNDLE_GEMFILE=Gemfile.rails-5.1 bundle && BUNDLE_GEMFILE=Gemfile.rails-5.1 bundle exec rspec spec