bullet 5.7.4 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -11
  3. data/Gemfile.rails-5.2 +1 -1
  4. data/README.md +7 -4
  5. data/Rakefile +1 -1
  6. data/bullet.gemspec +9 -3
  7. data/lib/bullet/active_record4.rb +15 -13
  8. data/lib/bullet/active_record41.rb +15 -13
  9. data/lib/bullet/active_record42.rb +16 -13
  10. data/lib/bullet/active_record5.rb +26 -13
  11. data/lib/bullet/active_record52.rb +21 -13
  12. data/lib/bullet/dependency.rb +3 -1
  13. data/lib/bullet/detector/association.rb +4 -2
  14. data/lib/bullet/detector/base.rb +2 -0
  15. data/lib/bullet/detector/counter_cache.rb +3 -0
  16. data/lib/bullet/detector/n_plus_one_query.rb +11 -9
  17. data/lib/bullet/detector/unused_eager_loading.rb +3 -0
  18. data/lib/bullet/detector.rb +2 -0
  19. data/lib/bullet/ext/object.rb +3 -1
  20. data/lib/bullet/ext/string.rb +3 -1
  21. data/lib/bullet/mongoid4x.rb +7 -2
  22. data/lib/bullet/mongoid5x.rb +7 -2
  23. data/lib/bullet/mongoid6x.rb +7 -4
  24. data/lib/bullet/notification/base.rb +3 -1
  25. data/lib/bullet/notification/counter_cache.rb +2 -0
  26. data/lib/bullet/notification/n_plus_one_query.rb +2 -0
  27. data/lib/bullet/notification/unused_eager_loading.rb +2 -0
  28. data/lib/bullet/notification.rb +2 -0
  29. data/lib/bullet/notification_collector.rb +2 -0
  30. data/lib/bullet/rack.rb +19 -15
  31. data/lib/bullet/registry/association.rb +2 -0
  32. data/lib/bullet/registry/base.rb +2 -0
  33. data/lib/bullet/registry/object.rb +2 -0
  34. data/lib/bullet/registry.rb +2 -0
  35. data/lib/bullet/stack_trace_filter.rb +43 -22
  36. data/lib/bullet/version.rb +3 -1
  37. data/lib/bullet.rb +5 -2
  38. data/lib/generators/bullet/install_generator.rb +5 -3
  39. data/perf/benchmark.rb +2 -0
  40. data/rails/init.rb +2 -0
  41. data/spec/bullet/detector/association_spec.rb +2 -0
  42. data/spec/bullet/detector/base_spec.rb +2 -0
  43. data/spec/bullet/detector/counter_cache_spec.rb +2 -0
  44. data/spec/bullet/detector/n_plus_one_query_spec.rb +25 -0
  45. data/spec/bullet/detector/unused_eager_loading_spec.rb +2 -0
  46. data/spec/bullet/ext/object_spec.rb +2 -0
  47. data/spec/bullet/ext/string_spec.rb +2 -0
  48. data/spec/bullet/notification/base_spec.rb +2 -0
  49. data/spec/bullet/notification/counter_cache_spec.rb +2 -0
  50. data/spec/bullet/notification/n_plus_one_query_spec.rb +2 -0
  51. data/spec/bullet/notification/unused_eager_loading_spec.rb +2 -0
  52. data/spec/bullet/notification_collector_spec.rb +2 -0
  53. data/spec/bullet/rack_spec.rb +2 -0
  54. data/spec/bullet/registry/association_spec.rb +2 -0
  55. data/spec/bullet/registry/base_spec.rb +2 -0
  56. data/spec/bullet/registry/object_spec.rb +2 -0
  57. data/spec/bullet_spec.rb +2 -0
  58. data/spec/integration/active_record/association_spec.rb +63 -1
  59. data/spec/integration/counter_cache_spec.rb +2 -0
  60. data/spec/integration/mongoid/association_spec.rb +2 -0
  61. data/spec/models/address.rb +2 -0
  62. data/spec/models/author.rb +2 -0
  63. data/spec/models/base_user.rb +2 -0
  64. data/spec/models/category.rb +2 -0
  65. data/spec/models/city.rb +2 -0
  66. data/spec/models/client.rb +4 -0
  67. data/spec/models/comment.rb +2 -0
  68. data/spec/models/company.rb +2 -0
  69. data/spec/models/country.rb +2 -0
  70. data/spec/models/document.rb +2 -0
  71. data/spec/models/entry.rb +2 -0
  72. data/spec/models/firm.rb +3 -0
  73. data/spec/models/folder.rb +2 -0
  74. data/spec/models/group.rb +4 -0
  75. data/spec/models/mongoid/address.rb +2 -0
  76. data/spec/models/mongoid/category.rb +2 -0
  77. data/spec/models/mongoid/comment.rb +2 -0
  78. data/spec/models/mongoid/company.rb +2 -0
  79. data/spec/models/mongoid/entry.rb +2 -0
  80. data/spec/models/mongoid/post.rb +2 -0
  81. data/spec/models/mongoid/user.rb +2 -0
  82. data/spec/models/newspaper.rb +2 -0
  83. data/spec/models/page.rb +2 -0
  84. data/spec/models/person.rb +2 -0
  85. data/spec/models/pet.rb +2 -0
  86. data/spec/models/post.rb +17 -0
  87. data/spec/models/relationship.rb +2 -0
  88. data/spec/models/reply.rb +2 -0
  89. data/spec/models/student.rb +2 -0
  90. data/spec/models/submission.rb +2 -0
  91. data/spec/models/teacher.rb +2 -0
  92. data/spec/models/user.rb +2 -0
  93. data/spec/models/writer.rb +2 -0
  94. data/spec/spec_helper.rb +2 -0
  95. data/spec/support/bullet_ext.rb +2 -0
  96. data/spec/support/mongo_seed.rb +4 -2
  97. data/spec/support/rack_double.rb +2 -0
  98. data/spec/support/sqlite_seed.rb +13 -4
  99. data/tasks/bullet_tasks.rake +2 -0
  100. metadata +9 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8dc58f03ac00764a73d88e5687a32895d94abcac
4
- data.tar.gz: bd8d3b6215063a5536489aeaab2ffbdc72cb85e3
3
+ metadata.gz: 0b65855ae5365567a18d1fb6ffdee5046b8cec35
4
+ data.tar.gz: 8df6b7afd18400dd2fe9bf39ec4a537fa04228af
5
5
  SHA512:
6
- metadata.gz: c19ffb78e51f2307ce792759149e67a8f354db648b1aa0a0a746c5153c2337596ca067bbec8ed12df536bb455502438df50fc23dce1c05c1595e31b488ff1c33
7
- data.tar.gz: 784d901307fbd9ba2286d6281e25229ea11e580a81b2dd7d5514a20b713faa72902d2c79ab6804d0ed93c61859cd1bb36955374b16e4101353329b318a8fa8d3
6
+ metadata.gz: 212cf02f1520dfaf752f794e42e9b2611fa0eca8b786bf5ef281c36c416ddf24016a524029614447c6241ebb734a2491ab554fa505544d7a7bc6f2e5b767527d
7
+ data.tar.gz: d2d71ceb54033f58cb6d675ea88268f130a0ea8bcfd7b4987486e374a2d2a3fc9169691ff20a9ca0fd9cf2787656dacc19649a8473879e9d1d68484597ccc18b
data/CHANGELOG.md CHANGED
@@ -1,22 +1,19 @@
1
1
  ## Next Release
2
2
 
3
- ## 5.7.4 (10/03/2018)
3
+ ## 5.8.0 (10/29/2018)
4
4
 
5
+ * Fix through reflection for rails 5.x
6
+ * Fix false positive in after_save/after_create callbacks
7
+ * Don't triger a preload error on "manual" preloads
5
8
  * Avoid Bullet from making extra queries in mongoid6
9
+ * Support option for #first and #last on mongoid6.x
10
+ * Fix duplicate logs in mongoid 4.x and 5.x version
6
11
  * Use caller for ruby 1.9 while caller_locations for 2.0+
7
-
8
- ## 5.7.3 (17/02/2018)
9
-
12
+ * Extend stacktrace matching for sub-file precision
10
13
  * Exclude configured bundler path in addition to '/vendor'
11
- * Support rails 5.1.5
12
-
13
- ## 5.7.2 (18/01/2018)
14
-
15
14
  * Fix `caller_path` in `excluded_stacktrace_path`
16
-
17
- ## 5.7.1 (07/01/2017)
18
-
19
15
  * Update `uniform_notifier` dependency to add Sentry support
16
+ * Integrate awesomecode.io and refactor code
20
17
 
21
18
  ## 5.7.0 (12/03/2017)
22
19
 
data/Gemfile.rails-5.2 CHANGED
@@ -2,7 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'rails', '~> 5.2.0.beta2'
5
+ gem 'rails', '~> 5.2.0'
6
6
  gem 'sqlite3'
7
7
  gem 'activerecord-jdbcsqlite3-adapter', platforms: [:jruby]
8
8
  gem 'activerecord-import'
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/bullet.png)](http://badge.fury.io/rb/bullet)
4
4
  [![Build Status](https://secure.travis-ci.org/flyerhzm/bullet.png)](http://travis-ci.org/flyerhzm/bullet)
5
- [![AwesomeCode Status](https://awesomecode.io/projects/6755235b-e2c1-459e-bf92-b8b13d0c0472/status)](https://awesomecode.io/projects/2)
5
+ [![AwesomeCode Status for flyerhzm/bullet](https://awesomecode.io/projects/6755235b-e2c1-459e-bf92-b8b13d0c0472/status)](https://awesomecode.io/repos/flyerhzm/bullet)
6
6
  [![Coderwall Endorse](http://api.coderwall.com/flyerhzm/endorsecount.png)](http://coderwall.com/flyerhzm)
7
7
 
8
8
  The Bullet gem is designed to help you increase your application's performance by reducing the number of queries it makes. It will watch your queries while you develop your application and notify you when you should add eager loading (N+1 queries), when you're using eager loading that isn't necessary and when you should use counter cache.
@@ -64,7 +64,7 @@ config.after_initialize do
64
64
  Bullet.rollbar = true
65
65
  Bullet.add_footer = true
66
66
  Bullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ]
67
- Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware' ]
67
+ Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware', ['my_file.rb', 'my_method'], ['my_file.rb', 16..20] ]
68
68
  Bullet.slack = { webhook_url: 'http://some.slack.url', channel: '#default', username: 'notifier' }
69
69
  end
70
70
  ```
@@ -87,6 +87,8 @@ The code above will enable all of the Bullet notification systems:
87
87
  * `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.
88
88
  * `Bullet.stacktrace_includes`: include paths with any of these substrings in the stack trace, even if they are not in your main app
89
89
  * `Bullet.stacktrace_excludes`: ignore paths with any of these substrings in the stack trace, even if they are not in your main app.
90
+ 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
91
+ item is a line number, a Range of line numbers, or a (bare) method name, to exclude only particular lines in a file.
90
92
  * `Bullet.slack`: add notifications to slack
91
93
  * `Bullet.raise`: raise errors, useful for making your specs fail unless they have optimized queries
92
94
 
@@ -126,10 +128,11 @@ class ApplicationController < ActionController::Base
126
128
  around_action :skip_bullet
127
129
 
128
130
  def skip_bullet
131
+ previous_value = Bullet.enable?
129
132
  Bullet.enable = false
130
133
  yield
131
134
  ensure
132
- Bullet.enable = true
135
+ Bullet.enable = previous_value
133
136
  end
134
137
  end
135
138
  ```
@@ -180,7 +183,7 @@ If you find Bullet does not work for you, *please disable your browser's cache*.
180
183
 
181
184
  ### Profile a job
182
185
 
183
- The Bullet gem uses rack middleware to profile requests. If you want to use Bullet without an http server, like to profile a job, you can use use profile method and fetch warnings
186
+ The Bullet gem uses rack middleware to profile requests. If you want to use Bullet without an http server, like to profile a job, you can use the profile method and fetch warnings
184
187
 
185
188
  ```ruby
186
189
  Bullet.profile do
data/Rakefile CHANGED
@@ -1,4 +1,4 @@
1
- $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
1
+ $LOAD_PATH.unshift File.expand_path('lib', __dir__)
2
2
  require 'bundler'
3
3
  Bundler.setup
4
4
 
data/bullet.gemspec CHANGED
@@ -1,4 +1,6 @@
1
- lib = File.expand_path('../lib/', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift lib unless $LOAD_PATH.include?(lib)
3
5
 
4
6
  require 'bullet/version'
@@ -12,13 +14,17 @@ Gem::Specification.new do |s|
12
14
  s.homepage = 'https://github.com/flyerhzm/bullet'
13
15
  s.summary = 'help to kill N+1 queries and unused eager loading.'
14
16
  s.description = 'help to kill N+1 queries and unused eager loading.'
17
+ s.metadata = {
18
+ 'changelog_uri' => 'https://github.com/flyerhzm/bullet/blob/master/CHANGELOG.md',
19
+ 'source_code_uri' => 'https://github.com/flyerhzm/bullet'
20
+ }
15
21
 
16
- s.license = 'MIT'
22
+ s.license = 'MIT'
17
23
 
18
24
  s.required_rubygems_version = '>= 1.3.6'
19
25
 
20
26
  s.add_runtime_dependency 'activesupport', '>= 3.0.0'
21
- s.add_runtime_dependency 'uniform_notifier', '~> 1.11.0'
27
+ s.add_runtime_dependency 'uniform_notifier', '~> 1.11'
22
28
 
23
29
  s.files = `git ls-files`.split("\n")
24
30
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module ActiveRecord
3
5
  def self.enable
@@ -46,21 +48,12 @@ module Bullet
46
48
  end
47
49
 
48
50
  ::ActiveRecord::Persistence.class_eval do
49
- def save_with_bullet(*args, &proc)
50
- was_new_record = new_record?
51
- save_without_bullet(*args, &proc).tap do |result|
52
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
53
- end
54
- end
55
- alias_method_chain :save, :bullet
56
-
57
- def save_with_bullet!(*args, &proc)
58
- was_new_record = new_record?
59
- save_without_bullet!(*args, &proc).tap do |result|
60
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
51
+ def _create_record_with_bullet(*args)
52
+ _create_record_without_bullet(*args).tap do
53
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
61
54
  end
62
55
  end
63
- alias_method_chain :save!, :bullet
56
+ alias_method_chain :_create_record, :bullet
64
57
  end
65
58
 
66
59
  ::ActiveRecord::Associations::Preloader.class_eval do
@@ -72,6 +65,7 @@ module Bullet
72
65
  if Bullet.start?
73
66
  records = [records].flatten.compact.uniq
74
67
  return if records.empty?
68
+
75
69
  records.each do |record|
76
70
  Bullet::Detector::Association.add_object_associations(record, associations)
77
71
  end
@@ -197,6 +191,14 @@ module Bullet
197
191
  end
198
192
  # rubocop:enable Style/MethodCallWithoutArgsParentheses
199
193
  end
194
+
195
+ ::ActiveRecord::Associations::BelongsToAssociation.class_eval do
196
+ def writer_with_bullet(record)
197
+ Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
198
+ writer_without_bullet(record)
199
+ end
200
+ alias_method_chain :writer, :bullet
201
+ end
200
202
  end
201
203
  end
202
204
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module ActiveRecord
3
5
  def self.enable
@@ -48,21 +50,12 @@ module Bullet
48
50
  end
49
51
 
50
52
  ::ActiveRecord::Persistence.class_eval do
51
- def save_with_bullet(*args, &proc)
52
- was_new_record = new_record?
53
- save_without_bullet(*args, &proc).tap do |result|
54
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
55
- end
56
- end
57
- alias_method_chain :save, :bullet
58
-
59
- def save_with_bullet!(*args, &proc)
60
- was_new_record = new_record?
61
- save_without_bullet!(*args, &proc).tap do |result|
62
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
53
+ def _create_record_with_bullet(*args)
54
+ _create_record_without_bullet(*args).tap do
55
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
63
56
  end
64
57
  end
65
- alias_method_chain :save!, :bullet
58
+ alias_method_chain :_create_record, :bullet
66
59
  end
67
60
 
68
61
  ::ActiveRecord::Associations::Preloader.class_eval do
@@ -87,6 +80,7 @@ module Bullet
87
80
  alias_method :origin_find_with_associations, :find_with_associations
88
81
  def find_with_associations
89
82
  return origin_find_with_associations { |r| yield r } if block_given?
83
+
90
84
  records = origin_find_with_associations
91
85
  if Bullet.start?
92
86
  associations = (eager_load_values + includes_values).uniq
@@ -185,6 +179,14 @@ module Bullet
185
179
  origin_count_records
186
180
  end
187
181
  end
182
+
183
+ ::ActiveRecord::Associations::BelongsToAssociation.class_eval do
184
+ def writer_with_bullet(record)
185
+ Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
186
+ writer_without_bullet(record)
187
+ end
188
+ alias_method_chain :writer, :bullet
189
+ end
188
190
  end
189
191
  end
190
192
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module ActiveRecord
3
5
  def self.enable
@@ -42,21 +44,12 @@ module Bullet
42
44
  end
43
45
 
44
46
  ::ActiveRecord::Persistence.class_eval do
45
- def save_with_bullet(*args, &proc)
46
- was_new_record = new_record?
47
- save_without_bullet(*args, &proc).tap do |result|
48
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
47
+ def _create_record_with_bullet(*args)
48
+ _create_record_without_bullet(*args).tap do
49
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
49
50
  end
50
51
  end
51
- alias_method_chain :save, :bullet
52
-
53
- def save_with_bullet!(*args, &proc)
54
- was_new_record = new_record?
55
- save_without_bullet!(*args, &proc).tap do |result|
56
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
57
- end
58
- end
59
- alias_method_chain :save!, :bullet
52
+ alias_method_chain :_create_record, :bullet
60
53
  end
61
54
 
62
55
  ::ActiveRecord::Relation.class_eval do
@@ -102,6 +95,7 @@ module Bullet
102
95
  alias_method :origin_find_with_associations, :find_with_associations
103
96
  def find_with_associations
104
97
  return origin_find_with_associations { |r| yield r } if block_given?
98
+
105
99
  records = origin_find_with_associations
106
100
  if Bullet.start?
107
101
  associations = (eager_load_values + includes_values).uniq
@@ -139,6 +133,7 @@ module Bullet
139
133
  key = aliases.column_alias(node, node.primary_key)
140
134
  id = row[key]
141
135
  next unless id.nil?
136
+
142
137
  associations = node.reflection.name
143
138
  Bullet::Detector::Association.add_object_associations(ar_parent, associations)
144
139
  Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
@@ -245,6 +240,14 @@ module Bullet
245
240
  origin_count_records
246
241
  end
247
242
  end
243
+
244
+ ::ActiveRecord::Associations::BelongsToAssociation.class_eval do
245
+ def writer_with_bullet(record)
246
+ Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
247
+ writer_without_bullet(record)
248
+ end
249
+ alias_method_chain :writer, :bullet
250
+ end
248
251
  end
249
252
  end
250
253
  end
@@ -1,16 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module SaveWithBulletSupport
3
- def save(*args)
4
- was_new_record = new_record?
5
- super(*args).tap do |result|
6
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
7
- end
8
- end
9
-
10
- def save!(*args)
11
- was_new_record = new_record?
12
- super(*args).tap do |result|
13
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
5
+ def _create_record(*)
6
+ super do
7
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
8
+ yield(self) if block_given?
14
9
  end
15
10
  end
16
11
  end
@@ -80,6 +75,7 @@ module Bullet
80
75
  # add includes in scope
81
76
  def find_with_associations
82
77
  return super { |r| yield r } if block_given?
78
+
83
79
  records = super
84
80
  if Bullet.start?
85
81
  associations = (eager_load_values + includes_values).uniq
@@ -130,6 +126,7 @@ module Bullet
130
126
  key = aliases.column_alias(node, node.primary_key)
131
127
  id = row[key]
132
128
  next unless id.nil?
129
+
133
130
  associations = node.reflection.name
134
131
  Bullet::Detector::Association.add_object_associations(ar_parent, associations)
135
132
  Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
@@ -166,11 +163,20 @@ module Bullet
166
163
 
167
164
  if Bullet.start?
168
165
  if is_a? ::ActiveRecord::Associations::ThroughAssociation
169
- Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
170
- association = owner.association through_reflection.name
166
+ refl = reflection.through_reflection
167
+ Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
168
+ association = owner.association refl.name
171
169
  Array(association.target).each do |through_record|
172
170
  Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
173
171
  end
172
+
173
+ if refl.through_reflection?
174
+ while refl.through_reflection?
175
+ refl = refl.through_reflection
176
+ end
177
+
178
+ Bullet::Detector::NPlusOneQuery.call_association(owner, refl.name)
179
+ end
174
180
  end
175
181
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
176
182
  if records.first.class.name !~ /^HABTM_/
@@ -236,6 +242,13 @@ module Bullet
236
242
  super
237
243
  end
238
244
  end)
245
+
246
+ ::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
247
+ def writer(record)
248
+ Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
249
+ super
250
+ end
251
+ end)
239
252
  end
240
253
  end
241
254
  end
@@ -1,16 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module SaveWithBulletSupport
3
- def save(*args)
4
- was_new_record = new_record?
5
- super(*args).tap do |result|
6
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
7
- end
8
- end
9
-
10
- def save!(*args)
11
- was_new_record = new_record?
12
- super(*args).tap do |result|
13
- Bullet::Detector::NPlusOneQuery.add_impossible_object(self) if result && was_new_record
5
+ def _create_record(*)
6
+ super do
7
+ Bullet::Detector::NPlusOneQuery.add_impossible_object(self)
8
+ yield(self) if block_given?
14
9
  end
15
10
  end
16
11
  end
@@ -80,6 +75,7 @@ module Bullet
80
75
  # add includes in scope
81
76
  def find_with_associations
82
77
  return super { |r| yield r } if block_given?
78
+
83
79
  records = super
84
80
  if Bullet.start?
85
81
  associations = (eager_load_values + includes_values).uniq
@@ -113,6 +109,7 @@ module Bullet
113
109
  key = aliases.column_alias(node, node.primary_key)
114
110
  id = row[key]
115
111
  next unless id.nil?
112
+
116
113
  associations = node.reflection.name
117
114
  Bullet::Detector::Association.add_object_associations(ar_parent, associations)
118
115
  Bullet::Detector::NPlusOneQuery.call_association(ar_parent, associations)
@@ -149,11 +146,15 @@ module Bullet
149
146
 
150
147
  if Bullet.start?
151
148
  if is_a? ::ActiveRecord::Associations::ThroughAssociation
152
- Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
153
- association = owner.association through_reflection.name
149
+ Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.through_reflection.name)
150
+ association = owner.association reflection.through_reflection.name
154
151
  Array(association.target).each do |through_record|
155
152
  Bullet::Detector::NPlusOneQuery.call_association(through_record, source_reflection.name)
156
153
  end
154
+
155
+ if reflection.through_reflection != through_reflection
156
+ Bullet::Detector::NPlusOneQuery.call_association(owner, through_reflection.name)
157
+ end
157
158
  end
158
159
  Bullet::Detector::NPlusOneQuery.call_association(owner, reflection.name) unless @inversed
159
160
  if records.first.class.name !~ /^HABTM_/
@@ -219,6 +220,13 @@ module Bullet
219
220
  super
220
221
  end
221
222
  end)
223
+
224
+ ::ActiveRecord::Associations::BelongsToAssociation.prepend(Module.new do
225
+ def writer(record)
226
+ Bullet::Detector::Association.add_object_associations(owner, reflection.name) if Bullet.start?
227
+ super
228
+ end
229
+ end)
222
230
  end
223
231
  end
224
232
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Dependency
3
5
  def mongoid?
@@ -27,7 +29,7 @@ module Bullet
27
29
  elsif active_record52?
28
30
  'active_record52'
29
31
  else
30
- raise "Bullet does not support active_record #{::ActiveRecord::VERSION} yet"
32
+ raise "Bullet does not support active_record #{::ActiveRecord::VERSION::STRING} yet"
31
33
  end
32
34
  end
33
35
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class Association < Base
@@ -7,7 +9,7 @@ module Bullet
7
9
  return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
8
10
  return unless object.primary_key_value
9
11
 
10
- Bullet.debug('Detector::Association#add_object_associations'.freeze, "object: #{object.bullet_key}, associations: #{associations}")
12
+ Bullet.debug('Detector::Association#add_object_associations', "object: #{object.bullet_key}, associations: #{associations}")
11
13
  object_associations.add(object.bullet_key, associations)
12
14
  end
13
15
 
@@ -16,7 +18,7 @@ module Bullet
16
18
  return if !Bullet.n_plus_one_query_enable? && !Bullet.unused_eager_loading_enable?
17
19
  return unless object.primary_key_value
18
20
 
19
- Bullet.debug('Detector::Association#add_call_object_associations'.freeze, "object: #{object.bullet_key}, associations: #{associations}")
21
+ Bullet.debug('Detector::Association#add_call_object_associations', "object: #{object.bullet_key}, associations: #{associations}")
20
22
  call_object_associations.add(object.bullet_key, associations)
21
23
  end
22
24
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class CounterCache < Base
@@ -16,6 +18,7 @@ module Bullet
16
18
  def add_possible_objects(object_or_objects)
17
19
  return unless Bullet.start?
18
20
  return unless Bullet.counter_cache_enable?
21
+
19
22
  objects = Array(object_or_objects)
20
23
  return if objects.map(&:primary_key_value).compact.empty?
21
24
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class NPlusOneQuery < Association
@@ -14,9 +16,10 @@ module Bullet
14
16
  return unless Bullet.n_plus_one_query_enable?
15
17
  return unless object.primary_key_value
16
18
  return if inversed_objects.include?(object.bullet_key, associations)
19
+
17
20
  add_call_object_associations(object, associations)
18
21
 
19
- Bullet.debug('Detector::NPlusOneQuery#call_association'.freeze, "object: #{object.bullet_key}, associations: #{associations}")
22
+ Bullet.debug('Detector::NPlusOneQuery#call_association', "object: #{object.bullet_key}, associations: #{associations}")
20
23
  if !excluded_stacktrace_path? && conditions_met?(object, associations)
21
24
  Bullet.debug('detect n + 1 query', "object: #{object.bullet_key}, associations: #{associations}")
22
25
  create_notification caller_in_project, object.class.to_s, associations
@@ -26,10 +29,11 @@ module Bullet
26
29
  def add_possible_objects(object_or_objects)
27
30
  return unless Bullet.start?
28
31
  return unless Bullet.n_plus_one_query_enable?
32
+
29
33
  objects = Array(object_or_objects)
30
34
  return if objects.map(&:primary_key_value).compact.empty?
31
35
 
32
- Bullet.debug('Detector::NPlusOneQuery#add_possible_objects'.freeze, "objects: #{objects.map(&:bullet_key).join(', '.freeze)}")
36
+ Bullet.debug('Detector::NPlusOneQuery#add_possible_objects', "objects: #{objects.map(&:bullet_key).join(', ')}")
33
37
  objects.each { |object| possible_objects.add object.bullet_key }
34
38
  end
35
39
 
@@ -38,7 +42,7 @@ module Bullet
38
42
  return unless Bullet.n_plus_one_query_enable?
39
43
  return unless object.primary_key_value
40
44
 
41
- Bullet.debug('Detector::NPlusOneQuery#add_impossible_object'.freeze, "object: #{object.bullet_key}")
45
+ Bullet.debug('Detector::NPlusOneQuery#add_impossible_object', "object: #{object.bullet_key}")
42
46
  impossible_objects.add object.bullet_key
43
47
  end
44
48
 
@@ -47,7 +51,7 @@ module Bullet
47
51
  return unless Bullet.n_plus_one_query_enable?
48
52
  return unless object.primary_key_value
49
53
 
50
- Bullet.debug('Detector::NPlusOneQuery#add_inversed_object'.freeze, "object: #{object.bullet_key}, association: #{association}")
54
+ Bullet.debug('Detector::NPlusOneQuery#add_inversed_object', "object: #{object.bullet_key}, association: #{association}")
51
55
  inversed_objects.add object.bullet_key, association
52
56
  end
53
57
 
@@ -67,14 +71,12 @@ module Bullet
67
71
  # check if object => associations already exists in object_associations.
68
72
  def association?(object, associations)
69
73
  value = object_associations[object.bullet_key]
70
- if value
71
- value.each do |v|
74
+ value&.each do |v|
72
75
  # associations == v comparison order is important here because
73
76
  # v variable might be a squeel node where :== method is redefined,
74
77
  # so it does not compare values at all and return unexpected results
75
- result = v.is_a?(Hash) ? v.key?(associations) : associations == v
76
- return true if result
77
- end
78
+ result = v.is_a?(Hash) ? v.key?(associations) : associations == v
79
+ return true if result
78
80
  end
79
81
 
80
82
  false
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  class UnusedEagerLoading < Association
@@ -73,6 +75,7 @@ module Bullet
73
75
  eager_loadings.similarly_associated(bullet_key, associations).each do |related_bullet_key|
74
76
  coa = call_object_associations[related_bullet_key]
75
77
  next if coa.nil?
78
+
76
79
  all.merge coa
77
80
  end
78
81
  all.to_a
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Detector
3
5
  autoload :Base, 'bullet/detector/base'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Object
2
4
  def bullet_key
3
5
  "#{self.class}:#{primary_key_value}"
@@ -5,7 +7,7 @@ class Object
5
7
 
6
8
  def primary_key_value
7
9
  if self.class.respond_to?(:primary_keys) && self.class.primary_keys
8
- self.class.primary_keys.map { |primary_key| send primary_key }.join(','.freeze)
10
+ self.class.primary_keys.map { |primary_key| send primary_key }.join(',')
9
11
  elsif self.class.respond_to?(:primary_key) && self.class.primary_key
10
12
  send self.class.primary_key
11
13
  else
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class String
2
4
  def bullet_class_name
3
- sub(/:[^:]*?$/, ''.freeze)
5
+ sub(/:[^:]*?$/, '')
4
6
  end
5
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bullet
2
4
  module Mongoid
3
5
  def self.enable
@@ -21,13 +23,16 @@ module Bullet
21
23
  end
22
24
 
23
25
  def each(&block)
24
- records = query.map { |doc| ::Mongoid::Factory.from_db(klass, doc) }
26
+ return to_enum unless block_given?
27
+
28
+ records = []
29
+ origin_each { |record| records << record }
25
30
  if records.length > 1
26
31
  Bullet::Detector::NPlusOneQuery.add_possible_objects(records)
27
32
  elsif records.size == 1
28
33
  Bullet::Detector::NPlusOneQuery.add_impossible_object(records.first)
29
34
  end
30
- origin_each(&block)
35
+ records.each(&block)
31
36
  end
32
37
 
33
38
  def eager_load(docs)