bullet 6.1.0 → 7.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +101 -2
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +48 -30
  5. data/lib/bullet/active_job.rb +5 -1
  6. data/lib/bullet/active_record4.rb +21 -6
  7. data/lib/bullet/active_record41.rb +22 -6
  8. data/lib/bullet/active_record42.rb +33 -12
  9. data/lib/bullet/active_record5.rb +50 -20
  10. data/lib/bullet/active_record52.rb +71 -36
  11. data/lib/bullet/active_record60.rb +70 -35
  12. data/lib/bullet/active_record61.rb +302 -0
  13. data/lib/bullet/active_record70.rb +318 -0
  14. data/lib/bullet/active_record71.rb +318 -0
  15. data/lib/bullet/bullet_xhr.js +18 -17
  16. data/lib/bullet/dependency.rb +28 -0
  17. data/lib/bullet/detector/association.rb +8 -0
  18. data/lib/bullet/detector/base.rb +2 -1
  19. data/lib/bullet/detector/counter_cache.rb +2 -2
  20. data/lib/bullet/detector/n_plus_one_query.rb +21 -13
  21. data/lib/bullet/detector/unused_eager_loading.rb +6 -3
  22. data/lib/bullet/ext/object.rb +14 -3
  23. data/lib/bullet/mongoid4x.rb +1 -1
  24. data/lib/bullet/mongoid5x.rb +1 -1
  25. data/lib/bullet/mongoid6x.rb +1 -1
  26. data/lib/bullet/mongoid7x.rb +32 -17
  27. data/lib/bullet/mongoid8x.rb +59 -0
  28. data/lib/bullet/notification/base.rb +22 -10
  29. data/lib/bullet/notification/counter_cache.rb +1 -1
  30. data/lib/bullet/notification.rb +2 -1
  31. data/lib/bullet/rack.rb +67 -24
  32. data/lib/bullet/registry/association.rb +2 -1
  33. data/lib/bullet/registry/call_stack.rb +12 -0
  34. data/lib/bullet/registry.rb +1 -0
  35. data/lib/bullet/stack_trace_filter.rb +16 -15
  36. data/lib/bullet/version.rb +1 -1
  37. data/lib/bullet.rb +45 -30
  38. data/lib/generators/bullet/install_generator.rb +22 -25
  39. metadata +13 -148
  40. data/.gitignore +0 -15
  41. data/.rspec +0 -2
  42. data/.travis.yml +0 -33
  43. data/Gemfile +0 -24
  44. data/Gemfile.mongoid +0 -12
  45. data/Gemfile.mongoid-4.0 +0 -15
  46. data/Gemfile.mongoid-5.0 +0 -15
  47. data/Gemfile.mongoid-6.0 +0 -15
  48. data/Gemfile.mongoid-7.0 +0 -15
  49. data/Gemfile.rails-4.0 +0 -16
  50. data/Gemfile.rails-4.1 +0 -16
  51. data/Gemfile.rails-4.2 +0 -16
  52. data/Gemfile.rails-5.0 +0 -15
  53. data/Gemfile.rails-5.1 +0 -15
  54. data/Gemfile.rails-5.2 +0 -15
  55. data/Gemfile.rails-6.0 +0 -15
  56. data/Guardfile +0 -8
  57. data/Hacking.md +0 -75
  58. data/Rakefile +0 -51
  59. data/bullet.gemspec +0 -33
  60. data/perf/benchmark.rb +0 -115
  61. data/rails/init.rb +0 -3
  62. data/spec/bullet/detector/association_spec.rb +0 -28
  63. data/spec/bullet/detector/base_spec.rb +0 -10
  64. data/spec/bullet/detector/counter_cache_spec.rb +0 -58
  65. data/spec/bullet/detector/n_plus_one_query_spec.rb +0 -182
  66. data/spec/bullet/detector/unused_eager_loading_spec.rb +0 -121
  67. data/spec/bullet/ext/object_spec.rb +0 -44
  68. data/spec/bullet/ext/string_spec.rb +0 -15
  69. data/spec/bullet/notification/base_spec.rb +0 -94
  70. data/spec/bullet/notification/counter_cache_spec.rb +0 -14
  71. data/spec/bullet/notification/n_plus_one_query_spec.rb +0 -31
  72. data/spec/bullet/notification/unused_eager_loading_spec.rb +0 -18
  73. data/spec/bullet/notification_collector_spec.rb +0 -34
  74. data/spec/bullet/rack_spec.rb +0 -153
  75. data/spec/bullet/registry/association_spec.rb +0 -28
  76. data/spec/bullet/registry/base_spec.rb +0 -46
  77. data/spec/bullet/registry/object_spec.rb +0 -26
  78. data/spec/bullet_spec.rb +0 -136
  79. data/spec/integration/active_record/association_spec.rb +0 -739
  80. data/spec/integration/counter_cache_spec.rb +0 -68
  81. data/spec/integration/mongoid/association_spec.rb +0 -246
  82. data/spec/models/address.rb +0 -5
  83. data/spec/models/author.rb +0 -5
  84. data/spec/models/base_user.rb +0 -7
  85. data/spec/models/category.rb +0 -12
  86. data/spec/models/city.rb +0 -5
  87. data/spec/models/client.rb +0 -8
  88. data/spec/models/comment.rb +0 -8
  89. data/spec/models/company.rb +0 -5
  90. data/spec/models/country.rb +0 -5
  91. data/spec/models/document.rb +0 -7
  92. data/spec/models/entry.rb +0 -5
  93. data/spec/models/firm.rb +0 -7
  94. data/spec/models/folder.rb +0 -3
  95. data/spec/models/group.rb +0 -3
  96. data/spec/models/mongoid/address.rb +0 -9
  97. data/spec/models/mongoid/category.rb +0 -10
  98. data/spec/models/mongoid/comment.rb +0 -9
  99. data/spec/models/mongoid/company.rb +0 -9
  100. data/spec/models/mongoid/entry.rb +0 -9
  101. data/spec/models/mongoid/post.rb +0 -14
  102. data/spec/models/mongoid/user.rb +0 -7
  103. data/spec/models/newspaper.rb +0 -5
  104. data/spec/models/page.rb +0 -3
  105. data/spec/models/person.rb +0 -5
  106. data/spec/models/pet.rb +0 -5
  107. data/spec/models/post.rb +0 -32
  108. data/spec/models/relationship.rb +0 -6
  109. data/spec/models/reply.rb +0 -5
  110. data/spec/models/student.rb +0 -5
  111. data/spec/models/submission.rb +0 -6
  112. data/spec/models/teacher.rb +0 -5
  113. data/spec/models/user.rb +0 -6
  114. data/spec/models/writer.rb +0 -3
  115. data/spec/spec_helper.rb +0 -99
  116. data/spec/support/bullet_ext.rb +0 -56
  117. data/spec/support/mongo_seed.rb +0 -58
  118. data/spec/support/rack_double.rb +0 -49
  119. data/spec/support/sqlite_seed.rb +0 -246
  120. data/test.sh +0 -13
  121. data/update.sh +0 -10
@@ -1,4 +1,4 @@
1
- (function() {
1
+ (function () {
2
2
  var oldOpen = window.XMLHttpRequest.prototype.open;
3
3
  var oldSend = window.XMLHttpRequest.prototype.send;
4
4
 
@@ -10,41 +10,42 @@
10
10
  if (isBulletInitiated()) return;
11
11
 
12
12
  function isBulletInitiated() {
13
- return oldOpen.name == 'bulletXHROpen' && oldSend.name == 'bulletXHRSend';
13
+ return oldOpen.name == "bulletXHROpen" && oldSend.name == "bulletXHRSend";
14
14
  }
15
15
  function bulletXHROpen(_, url) {
16
16
  this._storedUrl = url;
17
- return oldOpen.apply(this, arguments);
17
+ return Reflect.apply(oldOpen, this, arguments);
18
18
  }
19
19
  function bulletXHRSend() {
20
20
  if (this.onload) {
21
21
  this._storedOnload = this.onload;
22
22
  }
23
- this.addEventListener('load', bulletXHROnload);
24
- return oldSend.apply(this, arguments);
23
+ this.onload = null;
24
+ this.addEventListener("load", bulletXHROnload);
25
+ return Reflect.apply(oldSend, this, arguments);
25
26
  }
26
27
  function bulletXHROnload() {
27
28
  if (
28
- this._storedUrl.startsWith(window.location.protocol + '//' + window.location.host) ||
29
- !this._storedUrl.startsWith('http') // For relative paths
29
+ this._storedUrl.startsWith(window.location.protocol + "//" + window.location.host) ||
30
+ !this._storedUrl.startsWith("http") // For relative paths
30
31
  ) {
31
- var bulletFooterText = this.getResponseHeader('X-bullet-footer-text');
32
+ var bulletFooterText = this.getResponseHeader("X-bullet-footer-text");
32
33
  if (bulletFooterText) {
33
- setTimeout(() => {
34
- var oldHtml = document.getElementById('bullet-footer').innerHTML.split('<br>');
34
+ setTimeout(function () {
35
+ var oldHtml = document.querySelector("#bullet-footer").innerHTML.split("<br>");
35
36
  var header = oldHtml[0];
36
37
  oldHtml = oldHtml.slice(1, oldHtml.length);
37
38
  var newHtml = oldHtml.concat(JSON.parse(bulletFooterText));
38
39
  newHtml = newHtml.slice(newHtml.length - 10, newHtml.length); // rotate through 10 most recent
39
- document.getElementById('bullet-footer').innerHTML = `${header}<br>${newHtml.join('<br>')}`;
40
+ document.querySelector("#bullet-footer").innerHTML = `${header}<br>${newHtml.join("<br>")}`;
40
41
  }, 0);
41
42
  }
42
- var bulletConsoleText = this.getResponseHeader('X-bullet-console-text');
43
- if (bulletConsoleText && typeof console !== 'undefined' && console.log) {
44
- setTimeout(() => {
45
- JSON.parse(bulletConsoleText).forEach(message => {
43
+ var bulletConsoleText = this.getResponseHeader("X-bullet-console-text");
44
+ if (bulletConsoleText && typeof console !== "undefined" && console.log) {
45
+ setTimeout(function () {
46
+ JSON.parse(bulletConsoleText).forEach((message) => {
46
47
  if (console.groupCollapsed && console.groupEnd) {
47
- console.groupCollapsed('Uniform Notifier');
48
+ console.groupCollapsed("Uniform Notifier");
48
49
  console.log(message);
49
50
  console.groupEnd();
50
51
  } else {
@@ -55,7 +56,7 @@
55
56
  }
56
57
  }
57
58
  if (this._storedOnload) {
58
- return this._storedOnload.apply(this, arguments);
59
+ return Reflect.apply(this._storedOnload, this, arguments);
59
60
  }
60
61
  }
61
62
  window.XMLHttpRequest.prototype.open = bulletXHROpen;
@@ -27,6 +27,12 @@ module Bullet
27
27
  'active_record52'
28
28
  elsif active_record60?
29
29
  'active_record60'
30
+ elsif active_record61?
31
+ 'active_record61'
32
+ elsif active_record70?
33
+ 'active_record70'
34
+ elsif active_record71?
35
+ 'active_record71'
30
36
  else
31
37
  raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
32
38
  end
@@ -44,6 +50,8 @@ module Bullet
44
50
  'mongoid6x'
45
51
  elsif mongoid7x?
46
52
  'mongoid7x'
53
+ elsif mongoid8x?
54
+ 'mongoid8x'
47
55
  else
48
56
  raise "Bullet does not support mongoid #{::Mongoid::VERSION} yet"
49
57
  end
@@ -62,6 +70,10 @@ module Bullet
62
70
  active_record? && ::ActiveRecord::VERSION::MAJOR == 6
63
71
  end
64
72
 
73
+ def active_record7?
74
+ active_record? && ::ActiveRecord::VERSION::MAJOR == 7
75
+ end
76
+
65
77
  def active_record40?
66
78
  active_record4? && ::ActiveRecord::VERSION::MINOR == 0
67
79
  end
@@ -90,6 +102,18 @@ module Bullet
90
102
  active_record6? && ::ActiveRecord::VERSION::MINOR == 0
91
103
  end
92
104
 
105
+ def active_record61?
106
+ active_record6? && ::ActiveRecord::VERSION::MINOR == 1
107
+ end
108
+
109
+ def active_record70?
110
+ active_record7? && ::ActiveRecord::VERSION::MINOR == 0
111
+ end
112
+
113
+ def active_record71?
114
+ active_record7? && ::ActiveRecord::VERSION::MINOR == 1
115
+ end
116
+
93
117
  def mongoid4x?
94
118
  mongoid? && ::Mongoid::VERSION =~ /\A4/
95
119
  end
@@ -105,5 +129,9 @@ module Bullet
105
129
  def mongoid7x?
106
130
  mongoid? && ::Mongoid::VERSION =~ /\A7/
107
131
  end
132
+
133
+ def mongoid8x?
134
+ mongoid? && ::Mongoid::VERSION =~ /\A8/
135
+ end
108
136
  end
109
137
  end
@@ -13,6 +13,7 @@ module Bullet
13
13
  'Detector::Association#add_object_associations',
14
14
  "object: #{object.bullet_key}, associations: #{associations}"
15
15
  )
16
+ call_stacks.add(object.bullet_key)
16
17
  object_associations.add(object.bullet_key, associations)
17
18
  end
18
19
 
@@ -25,6 +26,7 @@ module Bullet
25
26
  'Detector::Association#add_call_object_associations',
26
27
  "object: #{object.bullet_key}, associations: #{associations}"
27
28
  )
29
+ call_stacks.add(object.bullet_key)
28
30
  call_object_associations.add(object.bullet_key, associations)
29
31
  end
30
32
 
@@ -76,6 +78,12 @@ module Bullet
76
78
  def eager_loadings
77
79
  Thread.current[:bullet_eager_loadings]
78
80
  end
81
+
82
+ # cal_stacks keeps stacktraces where querie-objects were called from.
83
+ # e.g. { 'Object:111' => [SomeProject/app/controllers/...] }
84
+ def call_stacks
85
+ Thread.current[:bullet_call_stacks]
86
+ end
79
87
  end
80
88
  end
81
89
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Bullet
4
4
  module Detector
5
- class Base; end
5
+ class Base
6
+ end
6
7
  end
7
8
  end
@@ -20,7 +20,7 @@ module Bullet
20
20
  return unless Bullet.start?
21
21
  return unless Bullet.counter_cache_enable?
22
22
 
23
- objects = Array(object_or_objects)
23
+ objects = Array.wrap(object_or_objects)
24
24
  return if objects.map(&:bullet_primary_key_value).compact.empty?
25
25
 
26
26
  Bullet.debug(
@@ -54,7 +54,7 @@ module Bullet
54
54
  private
55
55
 
56
56
  def create_notification(klazz, associations)
57
- notify_associations = Array(associations) - Bullet.get_whitelist_associations(:counter_cache, klazz)
57
+ notify_associations = Array.wrap(associations) - Bullet.get_safelist_associations(:counter_cache, klazz)
58
58
 
59
59
  if notify_associations.present?
60
60
  notice = Bullet::Notification::CounterCache.new klazz, notify_associations
@@ -7,7 +7,7 @@ module Bullet
7
7
  extend StackTraceFilter
8
8
 
9
9
  class << self
10
- # executed when object.assocations is called.
10
+ # executed when object.associations is called.
11
11
  # first, it keeps this method call for object.association.
12
12
  # then, it checks if this associations call is unpreload.
13
13
  # if it is, keeps this unpreload associations and caller.
@@ -25,7 +25,7 @@ module Bullet
25
25
  )
26
26
  if !excluded_stacktrace_path? && conditions_met?(object, associations)
27
27
  Bullet.debug('detect n + 1 query', "object: #{object.bullet_key}, associations: #{associations}")
28
- create_notification caller_in_project, object.class.to_s, associations
28
+ create_notification caller_in_project(object.bullet_key), object.class.to_s, associations
29
29
  end
30
30
  end
31
31
 
@@ -33,14 +33,23 @@ module Bullet
33
33
  return unless Bullet.start?
34
34
  return unless Bullet.n_plus_one_query_enable?
35
35
 
36
- objects = Array(object_or_objects)
37
- return if objects.map(&:bullet_primary_key_value).compact.empty?
38
-
39
- Bullet.debug(
40
- 'Detector::NPlusOneQuery#add_possible_objects',
41
- "objects: #{objects.map(&:bullet_key).join(', ')}"
42
- )
43
- objects.each { |object| possible_objects.add object.bullet_key }
36
+ objects = Array.wrap(object_or_objects)
37
+ class_names_match_regex = true
38
+ primary_key_values_are_empty = true
39
+ keys_joined = ""
40
+ objects.each do |obj|
41
+ unless obj.class.name =~ /^HABTM_/
42
+ class_names_match_regex = false
43
+ end
44
+ unless obj.bullet_primary_key_value.nil?
45
+ primary_key_values_are_empty = false
46
+ end
47
+ keys_joined += "#{(keys_joined.empty? ? '' : ', ')}#{obj.bullet_key}"
48
+ end
49
+ unless class_names_match_regex || primary_key_values_are_empty
50
+ Bullet.debug('Detector::NPlusOneQuery#add_possible_objects', "objects: #{keys_joined}")
51
+ objects.each { |object| possible_objects.add object.bullet_key }
52
+ end
44
53
  end
45
54
 
46
55
  def add_impossible_object(object)
@@ -84,8 +93,7 @@ module Bullet
84
93
  # associations == v comparison order is important here because
85
94
  # v variable might be a squeel node where :== method is redefined,
86
95
  # so it does not compare values at all and return unexpected results
87
- result =
88
- v.is_a?(Hash) ? v.key?(associations) : associations == v
96
+ result = v.is_a?(Hash) ? v.key?(associations) : associations == v
89
97
  return true if result
90
98
  end
91
99
 
@@ -95,7 +103,7 @@ module Bullet
95
103
  private
96
104
 
97
105
  def create_notification(callers, klazz, associations)
98
- notify_associations = Array(associations) - Bullet.get_whitelist_associations(:n_plus_one_query, klazz)
106
+ notify_associations = Array.wrap(associations) - Bullet.get_safelist_associations(:n_plus_one_query, klazz)
99
107
 
100
108
  if notify_associations.present?
101
109
  notice = Bullet::Notification::NPlusOneQuery.new(callers, klazz, notify_associations)
@@ -10,7 +10,7 @@ module Bullet
10
10
  # check if there are unused preload associations.
11
11
  # get related_objects from eager_loadings associated with object and associations
12
12
  # get call_object_association from associations of call_object_associations whose object is in related_objects
13
- # if association not in call_object_association, then the object => association - call_object_association is ununsed preload assocations
13
+ # if association not in call_object_association, then the object => association - call_object_association is unused preload associations
14
14
  def check_unused_preload_associations
15
15
  return unless Bullet.start?
16
16
  return unless Bullet.unused_eager_loading_enable?
@@ -20,7 +20,7 @@ module Bullet
20
20
  next if object_association_diff.empty?
21
21
 
22
22
  Bullet.debug('detect unused preload', "object: #{bullet_key}, associations: #{object_association_diff}")
23
- create_notification(caller_in_project, bullet_key.bullet_class_name, object_association_diff)
23
+ create_notification(caller_in_project(bullet_key), bullet_key.bullet_class_name, object_association_diff)
24
24
  end
25
25
  end
26
26
 
@@ -65,7 +65,10 @@ module Bullet
65
65
  private
66
66
 
67
67
  def create_notification(callers, klazz, associations)
68
- notify_associations = Array(associations) - Bullet.get_whitelist_associations(:unused_eager_loading, klazz)
68
+ notify_associations = Array.wrap(associations) - Bullet.get_safelist_associations(
69
+ :unused_eager_loading,
70
+ klazz
71
+ )
69
72
 
70
73
  if notify_associations.present?
71
74
  notice = Bullet::Notification::UnusedEagerLoading.new(callers, klazz, notify_associations)
@@ -9,11 +9,22 @@ class Object
9
9
  return if respond_to?(:persisted?) && !persisted?
10
10
 
11
11
  if self.class.respond_to?(:primary_keys) && self.class.primary_keys
12
- self.class.primary_keys.map { |primary_key| send primary_key }.join(',')
12
+ primary_key = self.class.primary_keys
13
13
  elsif self.class.respond_to?(:primary_key) && self.class.primary_key
14
- send self.class.primary_key
14
+ primary_key = self.class.primary_key
15
15
  else
16
- id
16
+ primary_key = :id
17
17
  end
18
+
19
+ bullet_join_potential_composite_primary_key(primary_key)
20
+ end
21
+
22
+ private
23
+
24
+ def bullet_join_potential_composite_primary_key(primary_keys)
25
+ return send(primary_keys) unless primary_keys.is_a?(Enumerable)
26
+
27
+ primary_keys.map { |primary_key| send primary_key }
28
+ .join(',')
18
29
  end
19
30
  end
@@ -23,7 +23,7 @@ module Bullet
23
23
  end
24
24
 
25
25
  def each(&block)
26
- return to_enum unless block_given?
26
+ return to_enum unless block
27
27
 
28
28
  records = []
29
29
  origin_each { |record| records << record }
@@ -23,7 +23,7 @@ module Bullet
23
23
  end
24
24
 
25
25
  def each(&block)
26
- return to_enum unless block_given?
26
+ return to_enum unless block
27
27
 
28
28
  records = []
29
29
  origin_each { |record| records << record }
@@ -23,7 +23,7 @@ module Bullet
23
23
  end
24
24
 
25
25
  def each(&block)
26
- return to_enum unless block_given?
26
+ return to_enum unless block
27
27
 
28
28
  records = []
29
29
  origin_each { |record| records << record }
@@ -4,35 +4,50 @@ module Bullet
4
4
  module Mongoid
5
5
  def self.enable
6
6
  require 'mongoid'
7
+ require 'rubygems'
7
8
  ::Mongoid::Contextual::Mongo.class_eval do
8
9
  alias_method :origin_first, :first
9
10
  alias_method :origin_last, :last
10
11
  alias_method :origin_each, :each
11
12
  alias_method :origin_eager_load, :eager_load
12
13
 
13
- def first(opts = {})
14
- result = origin_first(opts)
15
- Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
16
- result
17
- end
18
-
19
- def last(opts = {})
20
- result = origin_last(opts)
21
- Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
22
- result
14
+ %i[first last].each do |context|
15
+ default = Gem::Version.new(::Mongoid::VERSION) >= Gem::Version.new('7.5') ? nil : {}
16
+ define_method(context) do |opts = default|
17
+ result = send(:"origin_#{context}", opts)
18
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
19
+ result
20
+ end
23
21
  end
24
22
 
25
23
  def each(&block)
26
24
  return to_enum unless block_given?
27
25
 
28
- records = []
29
- origin_each { |record| records << record }
30
- if records.length > 1
31
- Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
32
- elsif records.size == 1
33
- Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
26
+ first_document = nil
27
+ document_count = 0
28
+
29
+ origin_each do |document|
30
+ document_count += 1
31
+
32
+ if document_count == 1
33
+ first_document = document
34
+ elsif document_count == 2
35
+ Bullet::Detector::NPlusOneQuery.add_possible_objects([first_document, document])
36
+ yield(first_document)
37
+ first_document = nil
38
+ yield(document)
39
+ else
40
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(document)
41
+ yield(document)
42
+ end
34
43
  end
35
- records.each(&block)
44
+
45
+ if document_count == 1
46
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(first_document)
47
+ yield(first_document)
48
+ end
49
+
50
+ self
36
51
  end
37
52
 
38
53
  def eager_load(docs)
@@ -0,0 +1,59 @@
1
+ module Bullet
2
+ module Mongoid
3
+ def self.enable
4
+ require 'mongoid'
5
+ ::Mongoid::Contextual::Mongo.class_eval do
6
+ alias_method :origin_first, :first
7
+ alias_method :origin_last, :last
8
+ alias_method :origin_each, :each
9
+ alias_method :origin_eager_load, :eager_load
10
+
11
+ def first(limit = nil)
12
+ result = origin_first(limit)
13
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
14
+ result
15
+ end
16
+
17
+ def last(limit = nil)
18
+ result = origin_last(limit)
19
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(result) if result
20
+ result
21
+ end
22
+
23
+ def each(&block)
24
+ return to_enum unless block_given?
25
+
26
+ records = []
27
+ origin_each { |record| records << record }
28
+ if records.length > 1
29
+ Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
30
+ elsif records.size == 1
31
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
32
+ end
33
+ records.each(&block)
34
+ end
35
+
36
+ def eager_load(docs)
37
+ associations = criteria.inclusions.map(&:name)
38
+ docs.each do |doc|
39
+ Bullet::Detector::NPlusOneQuery.add_object_associations(doc, associations)
40
+ end
41
+ Bullet::Detector::UnusedEagerLoading.add_eager_loadings(docs, associations)
42
+ origin_eager_load(docs)
43
+ end
44
+ end
45
+
46
+ ::Mongoid::Association::Accessors.class_eval do
47
+ alias_method :origin_get_relation, :get_relation
48
+
49
+ def get_relation(name, association, object, reload = false)
50
+ result = origin_get_relation(name, association, object, reload)
51
+ unless association.embedded?
52
+ Bullet::Detector::NPlusOneQuery.call_association(self, name)
53
+ end
54
+ result
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -28,13 +28,13 @@ module Bullet
28
28
  def whoami
29
29
  @user ||=
30
30
  ENV['USER'].presence ||
31
- (
32
- begin
33
- `whoami`.chomp
34
- rescue StandardError
35
- ''
36
- end
37
- )
31
+ (
32
+ begin
33
+ `whoami`.chomp
34
+ rescue StandardError
35
+ ''
36
+ end
37
+ )
38
38
  @user.present? ? "user: #{@user}" : ''
39
39
  end
40
40
 
@@ -51,11 +51,22 @@ module Bullet
51
51
  end
52
52
 
53
53
  def short_notice
54
- [whoami.presence, url, title, body].compact.join(' ')
54
+ parts = []
55
+ parts << whoami.presence unless Bullet.skip_user_in_notification
56
+ parts << url
57
+ parts << title
58
+ parts << body
59
+
60
+ parts.compact.join(' ')
55
61
  end
56
62
 
57
63
  def notification_data
58
- { user: whoami, url: url, title: title, body: body_with_caller }
64
+ hash = {}
65
+ hash[:user] = whoami unless Bullet.skip_user_in_notification
66
+ hash[:url] = url
67
+ hash[:title] = title
68
+ hash[:body] = body_with_caller
69
+ hash
59
70
  end
60
71
 
61
72
  def eql?(other)
@@ -73,7 +84,8 @@ module Bullet
73
84
  end
74
85
 
75
86
  def associations_str
76
- ".includes(#{@associations.map { |a| a.to_s.to_sym }.inspect})"
87
+ ".includes(#{@associations.map { |a| a.to_s.to_sym }
88
+ .inspect})"
77
89
  end
78
90
  end
79
91
  end
@@ -8,7 +8,7 @@ module Bullet
8
8
  end
9
9
 
10
10
  def title
11
- 'Need Counter Cache'
11
+ 'Need Counter Cache with Active Record size'
12
12
  end
13
13
  end
14
14
  end
@@ -7,6 +7,7 @@ module Bullet
7
7
  autoload :NPlusOneQuery, 'bullet/notification/n_plus_one_query'
8
8
  autoload :CounterCache, 'bullet/notification/counter_cache'
9
9
 
10
- class UnoptimizedQueryError < StandardError; end
10
+ class UnoptimizedQueryError < StandardError
11
+ end
11
12
  end
12
13
  end