bullet 2.2.0 → 2.3.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 (81) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +4 -1
  3. data/Gemfile +3 -2
  4. data/Gemfile.lock +85 -69
  5. data/Guardfile +8 -0
  6. data/README.textile +2 -2
  7. data/lib/bullet/action_controller2.rb +4 -4
  8. data/lib/bullet/active_record2.rb +5 -6
  9. data/lib/bullet/active_record3.rb +2 -3
  10. data/lib/bullet/active_record31.rb +10 -12
  11. data/lib/bullet/detector/association.rb +27 -53
  12. data/lib/bullet/detector/counter.rb +34 -29
  13. data/lib/bullet/detector/n_plus_one_query.rb +47 -28
  14. data/lib/bullet/detector/unused_eager_association.rb +31 -30
  15. data/lib/bullet/notification/base.rb +14 -12
  16. data/lib/bullet/notification/n_plus_one_query.rb +6 -10
  17. data/lib/bullet/notification/unused_eager_loading.rb +1 -2
  18. data/lib/bullet/notification_collector.rb +1 -2
  19. data/lib/bullet/rack.rb +6 -3
  20. data/lib/bullet/registry/association.rb +4 -6
  21. data/lib/bullet/registry/base.rb +10 -7
  22. data/lib/bullet/registry/object.rb +6 -6
  23. data/lib/bullet/version.rb +1 -1
  24. data/lib/bullet.rb +13 -8
  25. data/perf/benchmark.rb +30 -12
  26. data/spec/bullet/detector/association_spec.rb +90 -0
  27. data/spec/bullet/detector/base_spec.rb +14 -0
  28. data/spec/bullet/detector/counter_spec.rb +65 -0
  29. data/spec/bullet/detector/n_plus_one_query_spec.rb +94 -0
  30. data/spec/bullet/detector/unused_eager_association_spec.rb +62 -0
  31. data/spec/bullet/notification/base_spec.rb +67 -0
  32. data/spec/bullet/notification/counter_cache_spec.rb +12 -0
  33. data/spec/bullet/notification/n_plus_one_query_spec.rb +13 -0
  34. data/spec/bullet/notification/unused_eager_loading_spec.rb +12 -0
  35. data/spec/bullet/notification_collector_spec.rb +32 -0
  36. data/spec/bullet/rack_spec.rb +80 -24
  37. data/spec/bullet/registry/association_spec.rb +26 -0
  38. data/spec/bullet/registry/base_spec.rb +44 -0
  39. data/spec/bullet/registry/object_spec.rb +25 -0
  40. data/spec/integration/association_for_chris_spec.rb +37 -0
  41. data/spec/integration/association_for_peschkaj_spec.rb +26 -0
  42. data/spec/{bullet → integration}/association_spec.rb +1 -359
  43. data/spec/integration/counter_spec.rb +37 -0
  44. data/spec/models/address.rb +3 -0
  45. data/spec/models/author.rb +3 -0
  46. data/spec/models/base_user.rb +5 -0
  47. data/spec/models/category.rb +7 -0
  48. data/spec/models/city.rb +3 -0
  49. data/spec/models/client.rb +4 -0
  50. data/spec/models/comment.rb +4 -0
  51. data/spec/models/company.rb +3 -0
  52. data/spec/models/contact.rb +3 -0
  53. data/spec/models/country.rb +3 -0
  54. data/spec/models/deal.rb +4 -0
  55. data/spec/models/document.rb +5 -0
  56. data/spec/models/email.rb +3 -0
  57. data/spec/models/entry.rb +3 -0
  58. data/spec/models/firm.rb +4 -0
  59. data/spec/models/folder.rb +2 -0
  60. data/spec/models/hotel.rb +4 -0
  61. data/spec/models/location.rb +3 -0
  62. data/spec/models/newspaper.rb +3 -0
  63. data/spec/models/page.rb +2 -0
  64. data/spec/models/person.rb +3 -0
  65. data/spec/models/pet.rb +3 -0
  66. data/spec/models/post.rb +11 -0
  67. data/spec/models/relationship.rb +4 -0
  68. data/spec/models/student.rb +3 -0
  69. data/spec/models/submission.rb +4 -0
  70. data/spec/models/teacher.rb +3 -0
  71. data/spec/models/user.rb +4 -0
  72. data/spec/models/writer.rb +2 -0
  73. data/spec/spec_helper.rb +16 -106
  74. data/spec/support/bullet_ext.rb +55 -0
  75. data/spec/support/rack_double.rb +55 -0
  76. data/spec/support/seed.rb +256 -0
  77. metadata +104 -14
  78. data/.watchr +0 -24
  79. data/spec/bullet/association_for_chris_spec.rb +0 -96
  80. data/spec/bullet/association_for_peschkaj_spec.rb +0 -86
  81. data/spec/bullet/counter_spec.rb +0 -136
data/.gitignore CHANGED
@@ -7,3 +7,4 @@ coverage.data
7
7
  tags
8
8
  .bundle
9
9
  *.gem
10
+ benchmark_profile*
data/.travis.yml CHANGED
@@ -1 +1,4 @@
1
- rvm: 1.9.2
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ env: DB=sqlite
data/Gemfile CHANGED
@@ -5,11 +5,12 @@ source "http://rubygems.org"
5
5
  gemspec
6
6
 
7
7
  gem 'rails'
8
- gem 'sqlite3-ruby', :require => 'sqlite3'
8
+ gem 'sqlite3'
9
9
  gem 'mysql'
10
10
  gem 'activerecord-import'
11
11
 
12
12
  gem "rspec"
13
- gem "watchr"
13
+ gem "guard"
14
+ gem "guard-rspec"
14
15
 
15
16
  gem "perftools.rb"
data/Gemfile.lock CHANGED
@@ -1,95 +1,110 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bullet (2.2.0)
4
+ bullet (2.3.0)
5
5
  uniform_notifier (~> 1.0.0)
6
6
 
7
7
  GEM
8
8
  remote: http://rubygems.org/
9
9
  specs:
10
- abstract (1.0.0)
11
- actionmailer (3.0.11)
12
- actionpack (= 3.0.11)
13
- mail (~> 2.2.19)
14
- actionpack (3.0.11)
15
- activemodel (= 3.0.11)
16
- activesupport (= 3.0.11)
17
- builder (~> 2.1.2)
18
- erubis (~> 2.6.6)
19
- i18n (~> 0.5.0)
20
- rack (~> 1.2.1)
21
- rack-mount (~> 0.6.14)
22
- rack-test (~> 0.5.7)
23
- tzinfo (~> 0.3.23)
24
- activemodel (3.0.11)
25
- activesupport (= 3.0.11)
26
- builder (~> 2.1.2)
27
- i18n (~> 0.5.0)
28
- activerecord (3.0.11)
29
- activemodel (= 3.0.11)
30
- activesupport (= 3.0.11)
31
- arel (~> 2.0.10)
32
- tzinfo (~> 0.3.23)
33
- activerecord-import (0.2.5)
34
- activerecord (~> 3.0.0)
35
- activeresource (3.0.11)
36
- activemodel (= 3.0.11)
37
- activesupport (= 3.0.11)
38
- activesupport (3.0.11)
39
- arel (2.0.10)
40
- builder (2.1.2)
10
+ actionmailer (3.2.2)
11
+ actionpack (= 3.2.2)
12
+ mail (~> 2.4.0)
13
+ actionpack (3.2.2)
14
+ activemodel (= 3.2.2)
15
+ activesupport (= 3.2.2)
16
+ builder (~> 3.0.0)
17
+ erubis (~> 2.7.0)
18
+ journey (~> 1.0.1)
19
+ rack (~> 1.4.0)
20
+ rack-cache (~> 1.1)
21
+ rack-test (~> 0.6.1)
22
+ sprockets (~> 2.1.2)
23
+ activemodel (3.2.2)
24
+ activesupport (= 3.2.2)
25
+ builder (~> 3.0.0)
26
+ activerecord (3.2.2)
27
+ activemodel (= 3.2.2)
28
+ activesupport (= 3.2.2)
29
+ arel (~> 3.0.2)
30
+ tzinfo (~> 0.3.29)
31
+ activerecord-import (0.2.9)
32
+ activerecord (~> 3.0)
33
+ activerecord (~> 3.0)
34
+ activeresource (3.2.2)
35
+ activemodel (= 3.2.2)
36
+ activesupport (= 3.2.2)
37
+ activesupport (3.2.2)
38
+ i18n (~> 0.6)
39
+ multi_json (~> 1.0)
40
+ arel (3.0.2)
41
+ builder (3.0.0)
41
42
  diff-lcs (1.1.3)
42
- erubis (2.6.6)
43
- abstract (>= 1.0.0)
44
- i18n (0.5.0)
45
- json (1.6.3)
46
- mail (2.2.19)
47
- activesupport (>= 2.3.6)
43
+ erubis (2.7.0)
44
+ ffi (1.0.11)
45
+ guard (1.0.1)
46
+ ffi (>= 0.5.0)
47
+ thor (~> 0.14.6)
48
+ guard-rspec (0.6.0)
49
+ guard (>= 0.10.0)
50
+ hike (1.2.1)
51
+ i18n (0.6.0)
52
+ journey (1.0.3)
53
+ json (1.6.5)
54
+ mail (2.4.4)
48
55
  i18n (>= 0.4.0)
49
56
  mime-types (~> 1.16)
50
57
  treetop (~> 1.4.8)
51
- mime-types (1.17.2)
58
+ mime-types (1.18)
59
+ multi_json (1.1.0)
52
60
  mysql (2.8.1)
53
- perftools.rb (0.5.6)
61
+ perftools.rb (2.0.0)
54
62
  polyglot (0.3.3)
55
- rack (1.2.4)
56
- rack-mount (0.6.14)
57
- rack (>= 1.0.0)
58
- rack-test (0.5.7)
63
+ rack (1.4.1)
64
+ rack-cache (1.2)
65
+ rack (>= 0.4)
66
+ rack-ssl (1.3.2)
67
+ rack
68
+ rack-test (0.6.1)
59
69
  rack (>= 1.0)
60
- rails (3.0.11)
61
- actionmailer (= 3.0.11)
62
- actionpack (= 3.0.11)
63
- activerecord (= 3.0.11)
64
- activeresource (= 3.0.11)
65
- activesupport (= 3.0.11)
70
+ rails (3.2.2)
71
+ actionmailer (= 3.2.2)
72
+ actionpack (= 3.2.2)
73
+ activerecord (= 3.2.2)
74
+ activeresource (= 3.2.2)
75
+ activesupport (= 3.2.2)
66
76
  bundler (~> 1.0)
67
- railties (= 3.0.11)
68
- railties (3.0.11)
69
- actionpack (= 3.0.11)
70
- activesupport (= 3.0.11)
77
+ railties (= 3.2.2)
78
+ railties (3.2.2)
79
+ actionpack (= 3.2.2)
80
+ activesupport (= 3.2.2)
81
+ rack-ssl (~> 1.3.2)
71
82
  rake (>= 0.8.7)
72
83
  rdoc (~> 3.4)
73
- thor (~> 0.14.4)
84
+ thor (~> 0.14.6)
74
85
  rake (0.9.2.2)
75
- rdoc (3.11)
86
+ rdoc (3.12)
76
87
  json (~> 1.4)
77
- rspec (2.7.0)
78
- rspec-core (~> 2.7.0)
79
- rspec-expectations (~> 2.7.0)
80
- rspec-mocks (~> 2.7.0)
81
- rspec-core (2.7.1)
82
- rspec-expectations (2.7.0)
83
- diff-lcs (~> 1.1.2)
84
- rspec-mocks (2.7.0)
85
- sqlite3-ruby (1.3.2)
88
+ rspec (2.9.0)
89
+ rspec-core (~> 2.9.0)
90
+ rspec-expectations (~> 2.9.0)
91
+ rspec-mocks (~> 2.9.0)
92
+ rspec-core (2.9.0)
93
+ rspec-expectations (2.9.0)
94
+ diff-lcs (~> 1.1.3)
95
+ rspec-mocks (2.9.0)
96
+ sprockets (2.1.2)
97
+ hike (~> 1.2)
98
+ rack (~> 1.0)
99
+ tilt (~> 1.1, != 1.3.0)
100
+ sqlite3 (1.3.5)
86
101
  thor (0.14.6)
102
+ tilt (1.3.3)
87
103
  treetop (1.4.10)
88
104
  polyglot
89
105
  polyglot (>= 0.3.1)
90
- tzinfo (0.3.31)
106
+ tzinfo (0.3.32)
91
107
  uniform_notifier (1.0.1)
92
- watchr (0.7)
93
108
 
94
109
  PLATFORMS
95
110
  ruby
@@ -97,9 +112,10 @@ PLATFORMS
97
112
  DEPENDENCIES
98
113
  activerecord-import
99
114
  bullet!
115
+ guard
116
+ guard-rspec
100
117
  mysql
101
118
  perftools.rb
102
119
  rails
103
120
  rspec
104
- sqlite3-ruby
105
- watchr
121
+ sqlite3
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2, :all_after_pass => false, :all_on_start => false, :cli => "--color --format nested --fail-fast" do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/README.textile CHANGED
@@ -1,12 +1,12 @@
1
1
  h1. Bullet
2
2
 
3
- !https://secure.travis-ci.org/flyerhzm/rails_best_practices.png!:http://travis-ci.org/flyerhzm/rails_best_practices
3
+ !https://secure.travis-ci.org/flyerhzm/bullet.png!:http://travis-ci.org/flyerhzm/bullet
4
4
 
5
5
  The Bullet plugin/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.
6
6
 
7
7
  Best practice is to use Bullet in development mode or custom mode (staging, profile, etc.). The last thing you want is your clients getting alerts about how lazy you are.
8
8
 
9
- The Bullet plugin/gem now supports rails 2.1, 2.2, 2.3, 3.0 and 3.1.
9
+ The Bullet plugin/gem now supports rails 2.1, 2.2, 2.3, 3.0, 3.1 and 3.2.
10
10
 
11
11
  ****************************************************************************
12
12
 
@@ -2,8 +2,7 @@ module Bullet
2
2
  class ActionController
3
3
  def self.enable
4
4
  require 'action_controller'
5
- case Rails.version
6
- when /^2.3/
5
+ if Rails.version =~ /\A2.3/
7
6
  ::ActionController::Dispatcher.middleware.use Bullet::Rack
8
7
  ::ActionController::Dispatcher.class_eval do
9
8
  class <<self
@@ -14,7 +13,7 @@ module Bullet
14
13
  end
15
14
  end
16
15
  end
17
- when /^2.[2|1]/
16
+ elsif Rails.version =~ /\A2.[12]/
18
17
  ::ActionController::Dispatcher.class_eval do
19
18
  alias_method :origin_reload_application, :reload_application
20
19
  def reload_application
@@ -30,7 +29,8 @@ module Bullet
30
29
  response = origin_process(request, response, method = :perform_action, *arguments)
31
30
 
32
31
  if Bullet.notification?
33
- if response.headers["type"] and response.headers["type"].include? 'text/html' and response.body =~ %r{<html.*</html>}m
32
+ if response.headers["type"] && response.headers["type"].include?('text/html') &&
33
+ response.body.include?("<html>") && response.body.include?("</html>")
34
34
  response.body <<= Bullet.gather_inline_notifications
35
35
  response.headers["Content-Length"] = response.body.length.to_s
36
36
  end
@@ -1,5 +1,4 @@
1
1
  module Bullet
2
- LOAD_TARGET_RGX = /load_target/
3
2
  module ActiveRecord
4
3
  def self.enable
5
4
  require 'active_record'
@@ -11,7 +10,7 @@ module Bullet
11
10
  def find_every(options)
12
11
  records = origin_find_every(options)
13
12
 
14
- if records
13
+ if records
15
14
  if records.size > 1
16
15
  Bullet::Detector::Association.add_possible_objects(records)
17
16
  Bullet::Detector::Counter.add_possible_objects(records)
@@ -41,7 +40,7 @@ module Bullet
41
40
  end
42
41
  end
43
42
 
44
- ::ActiveRecord::Associations::ClassMethods.class_eval do
43
+ ::ActiveRecord::Associations::ClassMethods.class_eval do
45
44
  # add include in named_scope
46
45
  alias_method :origin_find_with_associations, :find_with_associations
47
46
  def find_with_associations(options)
@@ -75,19 +74,19 @@ module Bullet
75
74
  origin_load_target
76
75
  end
77
76
  end
78
-
77
+
79
78
  ::ActiveRecord::Associations::AssociationProxy.class_eval do
80
79
  # call has_one and belong_to association
81
80
  alias_method :origin_load_target, :load_target
82
81
  def load_target
83
82
  # avoid stack level too deep
84
83
  result = origin_load_target
85
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.find {|c| c =~ LOAD_TARGET_RGX }
84
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.any? {|c| c.include?("load_target") }
86
85
  Bullet::Detector::Association.add_possible_objects(result)
87
86
  result
88
87
  end
89
88
  end
90
-
89
+
91
90
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
92
91
  alias_method :origin_has_cached_counter?, :has_cached_counter?
93
92
  def has_cached_counter?
@@ -1,5 +1,4 @@
1
1
  module Bullet
2
- LOAD_TARGET_RGX = /load_target/
3
2
  module ActiveRecord
4
3
  def self.enable
5
4
  require 'active_record'
@@ -69,14 +68,14 @@ module Bullet
69
68
  origin_load_target
70
69
  end
71
70
  end
72
-
71
+
73
72
  ::ActiveRecord::Associations::AssociationProxy.class_eval do
74
73
  # call has_one and belong_to association
75
74
  alias_method :origin_load_target, :load_target
76
75
  def load_target
77
76
  # avoid stack level too deep
78
77
  result = origin_load_target
79
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.find {|c| c =~ LOAD_TARGET_RGX }
78
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.any? { |c| c.include?("load_target") }
80
79
  Bullet::Detector::Association.add_possible_objects(result)
81
80
  result
82
81
  end
@@ -1,5 +1,4 @@
1
1
  module Bullet
2
- LOAD_TARGET_RGX = /load_target/
3
2
  module ActiveRecord
4
3
  def self.enable
5
4
  require 'active_record'
@@ -69,14 +68,13 @@ module Bullet
69
68
  origin_load_target
70
69
  end
71
70
  end
72
-
73
- ::ActiveRecord::Associations::Association.class_eval do
74
- # call has_one and belong_to association
75
- alias_method :origin_load_target, :load_target
76
- def load_target
77
- # avoid stack level too deep
78
- result = origin_load_target
79
- Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name) unless caller.find {|c| c =~ LOAD_TARGET_RGX }
71
+
72
+ ::ActiveRecord::Associations::SingularAssociation.class_eval do
73
+ # call has_one and belongs_to associations
74
+ alias_method :origin_reader, :reader
75
+ def reader(force_reload = false)
76
+ result = origin_reader(force_reload)
77
+ Bullet::Detector::NPlusOneQuery.call_association(@owner, @reflection.name)
80
78
  Bullet::Detector::Association.add_possible_objects(result)
81
79
  result
82
80
  end
@@ -85,9 +83,9 @@ module Bullet
85
83
  ::ActiveRecord::Associations::HasManyAssociation.class_eval do
86
84
  alias_method :origin_has_cached_counter?, :has_cached_counter?
87
85
 
88
- def has_cached_counter?
89
- result = origin_has_cached_counter?
90
- Bullet::Detector::Counter.add_counter_cache(@owner, @reflection.name) unless result
86
+ def has_cached_counter?(reflection = reflection)
87
+ result = origin_has_cached_counter?(reflection)
88
+ Bullet::Detector::Counter.add_counter_cache(owner, reflection.name) unless result
91
89
  result
92
90
  end
93
91
  end
@@ -13,7 +13,6 @@ module Bullet
13
13
  # derive from Bullet::Detector::Association - changing the variable
14
14
  # in one subclass will make the change visible to all subclasses!
15
15
  @@object_associations = nil
16
- @@callers = nil
17
16
  @@possible_objects = nil
18
17
  @@impossible_objects = nil
19
18
  @@call_object_associations = nil
@@ -21,83 +20,62 @@ module Bullet
21
20
  end
22
21
 
23
22
  def add_object_associations(object, associations)
24
- object_associations.add( object, associations )
23
+ object_associations.add(object.ar_key, associations)
25
24
  end
26
25
 
27
26
  def add_call_object_associations(object, associations)
28
- call_object_associations.add( object, associations )
27
+ if object.id
28
+ call_object_associations.add(object.ar_key, associations)
29
+ end
29
30
  end
30
31
 
31
- def add_possible_objects(objects)
32
- possible_objects.add objects
32
+ def add_possible_objects(object_or_objects)
33
+ if object_or_objects.is_a? Array
34
+ object_or_objects.each { |object| possible_objects.add object.ar_key }
35
+ else
36
+ possible_objects.add object_or_objects.ar_key
37
+ end
33
38
  end
34
39
 
35
40
  def add_impossible_object(object)
36
- impossible_objects.add object
41
+ impossible_objects.add object.ar_key
37
42
  end
38
43
 
39
44
  def add_eager_loadings(objects, associations)
40
- objects = Array(objects)
45
+ object_ar_keys = Array(objects).map(&:ar_key)
41
46
 
42
47
  to_add = nil
43
48
  to_merge, to_delete = [], []
44
49
  eager_loadings.each do |k, v|
45
- key_objects_overlap = k & objects
50
+ key_objects_overlap = k & object_ar_keys
46
51
 
47
52
  next if key_objects_overlap.empty?
48
53
 
49
54
  if key_objects_overlap == k
50
55
  to_add = [k, associations]
51
56
  break
52
-
53
57
  else
54
58
  to_merge << [key_objects_overlap, ( eager_loadings[k].dup << associations )]
55
59
 
56
- keys_without_objects = k - objects
60
+ keys_without_objects = k - object_ar_keys
57
61
  to_merge << [keys_without_objects, eager_loadings[k]]
58
62
  to_delete << k
59
- objects = objects - k
63
+ object_ar_keys = object_ar_keys - k
60
64
  end
61
65
  end
62
- if to_add
63
- eager_loadings.add *to_add
64
- end
65
- to_merge.each do |k,val|
66
- eager_loadings.merge k, val
67
- end
68
- to_delete.each do |k|
69
- eager_loadings.delete k
70
- end
71
66
 
72
- eager_loadings.add objects, associations unless objects.empty?
67
+ eager_loadings.add *to_add if to_add
68
+ to_merge.each { |k,val| eager_loadings.merge k, val }
69
+ to_delete.each { |k| eager_loadings.delete k }
70
+
71
+ eager_loadings.add object_ar_keys, associations unless object_ar_keys.empty?
73
72
  end
74
73
 
75
74
  private
76
- def possible?(object)
77
- possible_objects.contains? object
78
- end
79
-
80
- def impossible?(object)
81
- impossible_objects.contains? object
82
- end
83
-
84
- # check if object => associations already exists in object_associations.
85
- def association?(object, associations)
86
- value = object_associations[object]
87
- if value
88
- value.each do |v|
89
- result = v.is_a?(Hash) ? v.has_key?(associations) : v == associations
90
- return true if result
91
- end
92
- end
93
-
94
- return false
95
- end
96
-
97
- # object_associations keep the object relationships
75
+ # object_associations keep the object relationships
98
76
  # that the object has many associations.
99
- # e.g. { <Post id:1> => [:comments] }
100
- # the object_associations keep all associations that may be or may no be
77
+ # e.g. { "Post:1" => [:comments] }
78
+ # the object_associations keep all associations that may be or may no be
101
79
  # unpreload associations or unused preload associations.
102
80
  def object_associations
103
81
  @@object_associations ||= Bullet::Registry::Base.new
@@ -105,7 +83,7 @@ module Bullet
105
83
 
106
84
  # call_object_assciations keep the object relationships
107
85
  # that object.associations is called.
108
- # e.g. { <Post id:1> => [:comments] }
86
+ # e.g. { "Post:1" => [:comments] }
109
87
  # they are used to detect unused preload associations.
110
88
  def call_object_associations
111
89
  @@call_object_associations ||= Bullet::Registry::Base.new
@@ -113,14 +91,14 @@ module Bullet
113
91
 
114
92
  # possible_objects keep the class to object relationships
115
93
  # that the objects may cause N+1 query.
116
- # e.g. { Post => [<Post id:1>, <Post id:2>] }
94
+ # e.g. { Post => ["Post:1", "Post:2"] }
117
95
  def possible_objects
118
96
  @@possible_objects ||= Bullet::Registry::Object.new
119
97
  end
120
98
 
121
99
  # impossible_objects keep the class to objects relationships
122
100
  # that the objects may not cause N+1 query.
123
- # e.g. { Post => [<Post id:1>, <Post id:2>] }
101
+ # e.g. { Post => ["Post:1", "Post:2"] }
124
102
  # Notice: impossible_objects are not accurate,
125
103
  # if find collection returns only one object, then the object is impossible object,
126
104
  # impossible_objects are used to avoid treating 1+1 query to N+1 query.
@@ -130,14 +108,10 @@ module Bullet
130
108
 
131
109
  # eager_loadings keep the object relationships
132
110
  # that the associations are preloaded by find :include.
133
- # e.g. { [<Post id:1>, <Post id:2>] => [:comments, :user] }
111
+ # e.g. { ["Post:1", "Post:2"] => [:comments, :user] }
134
112
  def eager_loadings
135
113
  @@eager_loadings ||= Bullet::Registry::Association.new
136
114
  end
137
-
138
- def callers
139
- @@callers ||= []
140
- end
141
115
  end
142
116
  end
143
117
  end
@@ -1,42 +1,47 @@
1
1
  module Bullet
2
2
  module Detector
3
3
  class Counter < Base
4
- def self.clear
5
- @@possible_objects = nil
6
- @@impossible_objects = nil
7
- end
4
+ class <<self
5
+ def clear
6
+ @@possible_objects = nil
7
+ @@impossible_objects = nil
8
+ end
8
9
 
9
- def self.add_counter_cache(object, associations)
10
- if conditions_met?( object, associations )
11
- create_notification object.class, associations
10
+ def add_counter_cache(object, associations)
11
+ if conditions_met?(object.ar_key, associations)
12
+ create_notification object.class.to_s, associations
13
+ end
12
14
  end
13
- end
14
15
 
15
- def self.add_possible_objects(objects)
16
- possible_objects.add objects
17
- end
16
+ def add_possible_objects(object_or_objects)
17
+ if object_or_objects.is_a? Array
18
+ object_or_objects.each { |object| possible_objects.add object.ar_key }
19
+ else
20
+ possible_objects.add object_or_objects.ar_key
21
+ end
22
+ end
18
23
 
19
- def self.add_impossible_object(object)
20
- impossible_objects.add object
21
- end
22
-
23
- private
24
- def self.create_notification( klazz, associations )
25
- notice = Bullet::Notification::CounterCache.new klazz, associations
26
- Bullet.notification_collector.add notice
27
- end
24
+ def add_impossible_object(object)
25
+ impossible_objects.add object.ar_key
26
+ end
28
27
 
29
- def self.possible_objects
30
- @@possible_objects ||= Bullet::Registry::Object.new
31
- end
28
+ private
29
+ def create_notification(klazz, associations)
30
+ notice = Bullet::Notification::CounterCache.new klazz, associations
31
+ Bullet.notification_collector.add notice
32
+ end
32
33
 
33
- def self.impossible_objects
34
- @@impossible_objects ||= Bullet::Registry::Object.new
35
- end
34
+ def possible_objects
35
+ @@possible_objects ||= Bullet::Registry::Object.new
36
+ end
37
+
38
+ def impossible_objects
39
+ @@impossible_objects ||= Bullet::Registry::Object.new
40
+ end
36
41
 
37
- def self.conditions_met?( object, associations )
38
- possible_objects.contains?( object ) and
39
- !impossible_objects.contains?( object )
42
+ def conditions_met?(object_ar_key, associations)
43
+ possible_objects.include?(object_ar_key) && !impossible_objects.include?(object_ar_key)
44
+ end
40
45
  end
41
46
  end
42
47
  end