bullet 1.6.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.
- data/MIT-LICENSE +20 -0
- data/README.textile +381 -0
- data/Rakefile +33 -0
- data/VERSION +1 -0
- data/bullet.gemspec +59 -0
- data/lib/bullet.rb +77 -0
- data/lib/bullet/action_controller.rb +16 -0
- data/lib/bullet/active_record.rb +105 -0
- data/lib/bullet/association.rb +267 -0
- data/lib/bullet/counter.rb +101 -0
- data/lib/bullet/logger.rb +9 -0
- data/lib/bullet/notification.rb +83 -0
- data/lib/bulletware.rb +42 -0
- data/rails/init.rb +1 -0
- data/spec/bullet_association_spec.rb +1044 -0
- data/spec/bullet_counter_spec.rb +136 -0
- data/spec/spec.opts +8 -0
- data/spec/spec_helper.rb +50 -0
- data/tasks/bullet_tasks.rake +9 -0
- metadata +75 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
module Bullet
|
2
|
+
class Counter
|
3
|
+
class <<self
|
4
|
+
include Bullet::Notification
|
5
|
+
|
6
|
+
def start_request
|
7
|
+
end
|
8
|
+
|
9
|
+
def end_request
|
10
|
+
clear
|
11
|
+
end
|
12
|
+
|
13
|
+
def clear
|
14
|
+
@@klazz_associations = nil
|
15
|
+
@@possible_objects = nil
|
16
|
+
@@impossible_objects = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def need_counter_caches?
|
20
|
+
!klazz_associations.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def notification?
|
24
|
+
need_counter_caches?
|
25
|
+
end
|
26
|
+
|
27
|
+
def notification_response
|
28
|
+
response = []
|
29
|
+
if need_counter_caches?
|
30
|
+
response << counter_cache_messages.join("\n")
|
31
|
+
end
|
32
|
+
response
|
33
|
+
end
|
34
|
+
|
35
|
+
def console_title
|
36
|
+
title = ["Need Counter Cache"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def log_messages(path = nil)
|
40
|
+
[counter_cache_messages(path)]
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_counter_cache(object, associations)
|
44
|
+
klazz = object.class
|
45
|
+
if (!possible_objects[klazz].nil? and possible_objects[klazz].include?(object)) and
|
46
|
+
(impossible_objects[klazz].nil? or !impossible_objects[klazz].include?(object))
|
47
|
+
klazz_associations[klazz] ||= []
|
48
|
+
klazz_associations[klazz] << associations
|
49
|
+
unique(klazz_associations[klazz])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_possible_objects(objects)
|
54
|
+
klazz = objects.first.class
|
55
|
+
possible_objects[klazz] ||= []
|
56
|
+
possible_objects[klazz] << objects
|
57
|
+
unique(possible_objects[klazz])
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_impossible_object(object)
|
61
|
+
klazz = object.class
|
62
|
+
impossible_objects[klazz] ||= []
|
63
|
+
impossible_objects[klazz] << object
|
64
|
+
impossible_objects[klazz].uniq!
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def counter_cache_messages(path = nil)
|
69
|
+
messages = []
|
70
|
+
klazz_associations.each do |klazz, associations|
|
71
|
+
messages << [
|
72
|
+
"Need Counter Cache",
|
73
|
+
" #{klazz} => [#{associations.map(&:inspect).join(', ')}]"
|
74
|
+
]
|
75
|
+
end
|
76
|
+
messages
|
77
|
+
end
|
78
|
+
|
79
|
+
def unique(array)
|
80
|
+
array.flatten!
|
81
|
+
array.uniq!
|
82
|
+
end
|
83
|
+
|
84
|
+
def call_stack_messages
|
85
|
+
[]
|
86
|
+
end
|
87
|
+
|
88
|
+
def klazz_associations
|
89
|
+
@@klazz_associations ||= {}
|
90
|
+
end
|
91
|
+
|
92
|
+
def possible_objects
|
93
|
+
@@possible_objects ||= {}
|
94
|
+
end
|
95
|
+
|
96
|
+
def impossible_objects
|
97
|
+
@@impossible_objects ||= {}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Bullet
|
2
|
+
class NotificationError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
module Notification
|
6
|
+
def notification?
|
7
|
+
end
|
8
|
+
|
9
|
+
def notification_response
|
10
|
+
end
|
11
|
+
|
12
|
+
def console_title
|
13
|
+
end
|
14
|
+
|
15
|
+
def log_message(path = nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
def javascript_notification
|
19
|
+
str = ''
|
20
|
+
if Bullet.alert || Bullet.console
|
21
|
+
response = notification_response
|
22
|
+
end
|
23
|
+
unless response.blank?
|
24
|
+
if Bullet.alert
|
25
|
+
str << wrap_js_association("alert(#{response.join("\n").inspect});")
|
26
|
+
end
|
27
|
+
if Bullet.console
|
28
|
+
code = <<-CODE
|
29
|
+
if (typeof(console) !== 'undefined') {
|
30
|
+
|
31
|
+
if (console.groupCollapsed && console.groupEnd && console.log) {
|
32
|
+
|
33
|
+
console.groupCollapsed(#{console_title.join(', ').inspect});
|
34
|
+
console.log(#{response.join("\n").inspect});
|
35
|
+
console.log(#{call_stack_messages.join("\n").inspect});
|
36
|
+
console.groupEnd();
|
37
|
+
|
38
|
+
} else if (console.log) {
|
39
|
+
|
40
|
+
console.log(#{response.join("\n").inspect});
|
41
|
+
}
|
42
|
+
}
|
43
|
+
CODE
|
44
|
+
str << wrap_js_association(code)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
str
|
48
|
+
end
|
49
|
+
|
50
|
+
def growl_notification
|
51
|
+
if Bullet.growl
|
52
|
+
response = notification_response
|
53
|
+
unless response.blank?
|
54
|
+
begin
|
55
|
+
growl = Growl.new('localhost', 'ruby-growl', ['Bullet Notification'], nil, Bullet.growl_password)
|
56
|
+
growl.notify('Bullet Notification', 'Bullet Notification', response.join("\n"))
|
57
|
+
rescue
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def log_notification(path)
|
64
|
+
if Bullet.bullet_logger || Bullet.rails_logger
|
65
|
+
Rails.logger.warn '' if Bullet.rails_logger
|
66
|
+
messages = log_messages(path)
|
67
|
+
messages.each do |message|
|
68
|
+
Bullet.logger.info(message.join("\n")) if Bullet.bullet_logger
|
69
|
+
Rails.logger.warn(message.join("\n")) if Bullet.rails_logger
|
70
|
+
end
|
71
|
+
Bullet.logger_file.flush if Bullet.bullet_logger
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
def wrap_js_association(message)
|
77
|
+
str = ''
|
78
|
+
str << "<script type=\"text/javascript\">/*<![CDATA[*/"
|
79
|
+
str << message
|
80
|
+
str << "/*]]>*/</script>\n"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/bulletware.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
class Bulletware
|
2
|
+
def initialize(app)
|
3
|
+
@app = app
|
4
|
+
end
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
return @app.call(env) unless Bullet.enable?
|
8
|
+
|
9
|
+
Bullet.start_request
|
10
|
+
status, headers, response = @app.call(env)
|
11
|
+
return [status, headers, response] if empty?(response)
|
12
|
+
|
13
|
+
if Bullet.notification?
|
14
|
+
if check_html?(headers, response)
|
15
|
+
response_body = response.body << Bullet.javascript_notification
|
16
|
+
headers['Content-Length'] = response_body.length.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
Bullet.growl_notification
|
20
|
+
Bullet.log_notification(env['PATH_INFO'])
|
21
|
+
end
|
22
|
+
response_body ||= response.body
|
23
|
+
Bullet.end_request
|
24
|
+
no_browser_cache(headers) if Bullet.disable_browser_cache
|
25
|
+
[status, headers, response_body]
|
26
|
+
end
|
27
|
+
|
28
|
+
# fix issue if response's body is a Proc
|
29
|
+
def empty?(response)
|
30
|
+
(response.is_a?(Array) && response.empty?) || !response.body.is_a?(String) || response.body.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
def check_html?(headers, response)
|
34
|
+
!headers['Content-Type'].nil? and headers['Content-Type'].include? 'text/html' and response.body =~ %r{<html.*</html>}m
|
35
|
+
end
|
36
|
+
|
37
|
+
def no_browser_cache(headers)
|
38
|
+
headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
|
39
|
+
headers["Pragma"] = "no-cache"
|
40
|
+
headers["Expires"] = "Wed, 09 Sep 2009 09:09:09 GMT"
|
41
|
+
end
|
42
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bullet'
|
@@ -0,0 +1,1044 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
4
|
+
|
5
|
+
describe Bullet::Association, 'has_many' do
|
6
|
+
|
7
|
+
include BulletTestHelper
|
8
|
+
|
9
|
+
def setup_db
|
10
|
+
ActiveRecord::Schema.define(:version => 1) do
|
11
|
+
create_table :categories do |t|
|
12
|
+
t.column :name, :string
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :posts do |t|
|
16
|
+
t.column :name, :string
|
17
|
+
t.column :category_id, :integer
|
18
|
+
t.column :writer_id, :integer
|
19
|
+
end
|
20
|
+
|
21
|
+
create_table :comments do |t|
|
22
|
+
t.column :name, :string
|
23
|
+
t.column :post_id, :integer
|
24
|
+
t.column :author_id, :integer
|
25
|
+
end
|
26
|
+
|
27
|
+
create_table :entries do |t|
|
28
|
+
t.column :name, :string
|
29
|
+
t.column :category_id, :integer
|
30
|
+
end
|
31
|
+
|
32
|
+
create_table :base_users do |t|
|
33
|
+
t.column :name, :string
|
34
|
+
t.column :type, :string
|
35
|
+
t.column :newspaper_id, :integer
|
36
|
+
end
|
37
|
+
create_table :newspapers do |t|
|
38
|
+
t.column :name, :string
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def teardown_db
|
44
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
45
|
+
ActiveRecord::Base.connection.drop_table(table)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Category < ActiveRecord::Base
|
50
|
+
has_many :posts
|
51
|
+
has_many :entries
|
52
|
+
end
|
53
|
+
|
54
|
+
class Post < ActiveRecord::Base
|
55
|
+
belongs_to :category
|
56
|
+
has_many :comments
|
57
|
+
belongs_to :writer
|
58
|
+
|
59
|
+
|
60
|
+
named_scope :preload_posts, lambda { {:include => :comments} }
|
61
|
+
named_scope :in_category_name, lambda { |name|
|
62
|
+
{ :conditions => ['categories.name = ?', name], :include => :category }
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
class Entry < ActiveRecord::Base
|
67
|
+
belongs_to :category
|
68
|
+
end
|
69
|
+
|
70
|
+
class Comment < ActiveRecord::Base
|
71
|
+
belongs_to :post
|
72
|
+
belongs_to :author, :class_name => "BaseUser"
|
73
|
+
end
|
74
|
+
|
75
|
+
class BaseUser < ActiveRecord::Base
|
76
|
+
has_many :comments
|
77
|
+
has_many :posts
|
78
|
+
belongs_to :newspaper
|
79
|
+
end
|
80
|
+
|
81
|
+
class Newspaper < ActiveRecord::Base
|
82
|
+
has_many :writers, :class_name => "BaseUser"
|
83
|
+
end
|
84
|
+
|
85
|
+
class Writer < BaseUser
|
86
|
+
end
|
87
|
+
|
88
|
+
before(:all) do
|
89
|
+
silence_logger { setup_db }
|
90
|
+
|
91
|
+
newspaper1 = Newspaper.create(:name => "First Newspaper")
|
92
|
+
newspaper2 = Newspaper.create(:name => "Second Newspaper")
|
93
|
+
|
94
|
+
writer1 = Writer.create(:name => 'first', :newspaper => newspaper1)
|
95
|
+
writer2 = Writer.create(:name => 'second', :newspaper => newspaper2)
|
96
|
+
user1 = BaseUser.create(:name => 'third', :newspaper => newspaper1)
|
97
|
+
user2 = BaseUser.create(:name => 'fourth', :newspaper => newspaper2)
|
98
|
+
|
99
|
+
|
100
|
+
category1 = Category.create(:name => 'first')
|
101
|
+
category2 = Category.create(:name => 'second')
|
102
|
+
|
103
|
+
post1 = category1.posts.create(:name => 'first', :writer => writer1)
|
104
|
+
post1a = category1.posts.create(:name => 'like first', :writer => writer2)
|
105
|
+
post2 = category2.posts.create(:name => 'second', :writer => writer2)
|
106
|
+
|
107
|
+
comment1 = post1.comments.create(:name => 'first', :author => writer1)
|
108
|
+
comment2 = post1.comments.create(:name => 'first2', :author => writer1)
|
109
|
+
comment3 = post1.comments.create(:name => 'first3', :author => writer1)
|
110
|
+
comment4 = post1.comments.create(:name => 'second', :author => writer2)
|
111
|
+
comment8 = post1a.comments.create(:name => "like first 1", :author => writer1)
|
112
|
+
comment9 = post1a.comments.create(:name => "like first 2", :author => writer2)
|
113
|
+
comment5 = post2.comments.create(:name => 'third', :author => user1)
|
114
|
+
comment6 = post2.comments.create(:name => 'fourth', :author => user2)
|
115
|
+
comment7 = post2.comments.create(:name => 'fourth', :author => writer1)
|
116
|
+
|
117
|
+
entry1 = category1.entries.create(:name => 'first')
|
118
|
+
entry2 = category1.entries.create(:name => 'second')
|
119
|
+
end
|
120
|
+
|
121
|
+
after(:all) do
|
122
|
+
teardown_db
|
123
|
+
end
|
124
|
+
|
125
|
+
before(:each) do
|
126
|
+
Bullet::Association.start_request
|
127
|
+
end
|
128
|
+
|
129
|
+
after(:each) do
|
130
|
+
Bullet::Association.end_request
|
131
|
+
end
|
132
|
+
|
133
|
+
context "for unused cases" do
|
134
|
+
#If you have the same record created twice with different includes
|
135
|
+
# the hash value get's accumulated includes, which leads to false Unused eager loading
|
136
|
+
it "should not incorrectly mark associations as unused when multiple object instances" do
|
137
|
+
comments_with_author = Comment.all(:include => :author)
|
138
|
+
comments_with_post = Comment.all(:include => :post)
|
139
|
+
comments_with_author.each { |c| c.author.name }
|
140
|
+
comments_with_author.each { |c| c.post.name }
|
141
|
+
Bullet::Association.check_unused_preload_associations
|
142
|
+
Bullet::Association.should be_unused_preload_associations_for(Comment, :post)
|
143
|
+
Bullet::Association.should be_detecting_unpreloaded_association_for(Comment, :post)
|
144
|
+
end
|
145
|
+
|
146
|
+
# same as above with different Models being queried
|
147
|
+
it "should not incorrectly mark associations as unused when multiple object instances different Model" do
|
148
|
+
post_with_comments = Post.all(:include => :comments)
|
149
|
+
comments_with_author = Comment.all(:include => :author)
|
150
|
+
post_with_comments.each { |p| p.comments.first.author.name }
|
151
|
+
comments_with_author.each { |c| c.name }
|
152
|
+
Bullet::Association.check_unused_preload_associations
|
153
|
+
Bullet::Association.should be_unused_preload_associations_for(Comment, :author)
|
154
|
+
Bullet::Association.should be_detecting_unpreloaded_association_for(Comment, :author)
|
155
|
+
end
|
156
|
+
|
157
|
+
# this test passes right now. But is a regression test to ensure that if only a small set of returned records
|
158
|
+
# is not used that a unused preload association error is not generated
|
159
|
+
it "should not have unused when small set of returned records are discarded" do
|
160
|
+
comments_with_author = Comment.all(:include => :author)
|
161
|
+
comment_collection = comments_with_author.first(2)
|
162
|
+
comment_collection.collect { |com| com.author.name }
|
163
|
+
Bullet::Association.check_unused_preload_associations
|
164
|
+
Bullet::Association.should_not be_unused_preload_associations_for(Comment, :author)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
context "comments => posts => category" do
|
170
|
+
|
171
|
+
# this happens because the post isn't a possible object even though the writer is access through the post
|
172
|
+
# which leads to an 1+N queries
|
173
|
+
it "should detect unpreloaded writer" do
|
174
|
+
Comment.all(:include => [:author, :post],
|
175
|
+
:conditions => ["base_users.id = ?", BaseUser.first]).each do |com|
|
176
|
+
com.post.writer.name
|
177
|
+
end
|
178
|
+
Bullet::Association.should be_detecting_unpreloaded_association_for(Post, :writer)
|
179
|
+
end
|
180
|
+
|
181
|
+
# this happens because the comment doesn't break down the hash into keys
|
182
|
+
# properly creating an association from comment to post
|
183
|
+
it "should detect preload of comment => post" do
|
184
|
+
comments = Comment.all(:include => [:author, {:post => :writer}],
|
185
|
+
:conditions => ["base_users.id = ?", BaseUser.first]).each do |com|
|
186
|
+
com.post.writer.name
|
187
|
+
end
|
188
|
+
Bullet::Association.should_not be_detecting_unpreloaded_association_for(Comment, :post)
|
189
|
+
Bullet::Association.should be_completely_preloading_associations
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should detect preload of post => writer" do
|
193
|
+
comments = Comment.all(:include => [:author, {:post => :writer}],
|
194
|
+
:conditions => ["base_users.id = ?", BaseUser.first]).each do |com|
|
195
|
+
com.post.writer.name
|
196
|
+
end
|
197
|
+
Bullet::Association.should be_creating_object_association_for(comments.first, :author)
|
198
|
+
Bullet::Association.should_not be_detecting_unpreloaded_association_for(Post, :writer)
|
199
|
+
Bullet::Association.should be_completely_preloading_associations
|
200
|
+
end
|
201
|
+
|
202
|
+
# To flyerhzm: This does not detect that newspaper is unpreloaded. The association is
|
203
|
+
# not within possible objects, and thus cannot be detected as unpreloaded
|
204
|
+
it "should detect unpreloading of writer => newspaper" do
|
205
|
+
comments = Comment.all(:include => {:post => :writer}, :conditions => "posts.name like '%first%'").each do |com|
|
206
|
+
com.post.writer.newspaper.name
|
207
|
+
end
|
208
|
+
Bullet::Association.should be_detecting_unpreloaded_association_for(Writer, :newspaper)
|
209
|
+
end
|
210
|
+
|
211
|
+
# when we attempt to access category, there is an infinite overflow because load_target is hijacked leading to
|
212
|
+
# a repeating loop of calls in this test
|
213
|
+
it "should not raise a stack error from posts to category" do
|
214
|
+
lambda {
|
215
|
+
Comment.all(:include => {:post => :category}).each do |com|
|
216
|
+
com.post.category
|
217
|
+
end
|
218
|
+
}.should_not raise_error(SystemStackError)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context "post => comments" do
|
223
|
+
it "should detect preload with post => comments" do
|
224
|
+
Post.find(:all, :include => :comments).each do |post|
|
225
|
+
post.comments.collect(&:name)
|
226
|
+
end
|
227
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should detect no preload post => comments" do
|
231
|
+
Post.find(:all).each do |post|
|
232
|
+
post.comments.collect(&:name)
|
233
|
+
end
|
234
|
+
Bullet::Association.should be_has_unpreload_associations
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should detect unused preload post => comments for post" do
|
238
|
+
Post.find(:all, :include => :comments).collect(&:name)
|
239
|
+
Bullet::Association.check_unused_preload_associations
|
240
|
+
Bullet::Association.should be_has_unused_preload_associations
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should detect no unused preload post => comments for post" do
|
244
|
+
Post.find(:all).collect(&:name)
|
245
|
+
Bullet::Association.check_unused_preload_associations
|
246
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should detect no unused preload post => comments for comment" do
|
250
|
+
Post.find(:all).each do |post|
|
251
|
+
post.comments.collect(&:name)
|
252
|
+
end
|
253
|
+
Bullet::Association.check_unused_preload_associations
|
254
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
255
|
+
|
256
|
+
Bullet::Association.end_request
|
257
|
+
Bullet::Association.start_request
|
258
|
+
|
259
|
+
Post.find(:all).each do |post|
|
260
|
+
post.comments.collect(&:name)
|
261
|
+
end
|
262
|
+
Bullet::Association.check_unused_preload_associations
|
263
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
context "category => posts => comments" do
|
268
|
+
it "should detect preload with category => posts => comments" do
|
269
|
+
Category.find(:all, :include => {:posts => :comments}).each do |category|
|
270
|
+
category.posts.each do |post|
|
271
|
+
post.comments.collect(&:name)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should detect preload category => posts, but no post => comments" do
|
278
|
+
Category.find(:all, :include => :posts).each do |category|
|
279
|
+
category.posts.each do |post|
|
280
|
+
post.comments.collect(&:name)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
Bullet::Association.should be_has_unpreload_associations
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should detect no preload category => posts => comments" do
|
287
|
+
Category.find(:all).each do |category|
|
288
|
+
category.posts.each do |post|
|
289
|
+
post.comments.collect(&:name)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
Bullet::Association.should be_has_unpreload_associations
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should detect unused preload with category => posts => comments" do
|
296
|
+
Category.find(:all, :include => {:posts => :comments}).collect(&:name)
|
297
|
+
Bullet::Association.check_unused_preload_associations
|
298
|
+
Bullet::Association.should be_has_unused_preload_associations
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should detect unused preload with post => commnets, no category => posts" do
|
302
|
+
Category.find(:all, :include => {:posts => :comments}).each do |category|
|
303
|
+
category.posts.collect(&:name)
|
304
|
+
end
|
305
|
+
Bullet::Association.check_unused_preload_associations
|
306
|
+
Bullet::Association.should be_has_unused_preload_associations
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should no detect preload with category => posts => comments" do
|
310
|
+
Category.find(:all).each do |category|
|
311
|
+
category.posts.each do |post|
|
312
|
+
post.comments.collect(&:name)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
Bullet::Association.check_unused_preload_associations
|
316
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
context "category => posts, category => entries" do
|
321
|
+
it "should detect preload with category => [posts, entries]" do
|
322
|
+
Category.find(:all, :include => [:posts, :entries]).each do |category|
|
323
|
+
category.posts.collect(&:name)
|
324
|
+
category.entries.collect(&:name)
|
325
|
+
end
|
326
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
327
|
+
end
|
328
|
+
|
329
|
+
it "should detect preload with category => posts, but no category => entries" do
|
330
|
+
Category.find(:all, :include => :posts).each do |category|
|
331
|
+
category.posts.collect(&:name)
|
332
|
+
category.entries.collect(&:name)
|
333
|
+
end
|
334
|
+
Bullet::Association.should be_has_unpreload_associations
|
335
|
+
end
|
336
|
+
|
337
|
+
it "should detect no preload with category => [posts, entries]" do
|
338
|
+
Category.find(:all).each do |category|
|
339
|
+
category.posts.collect(&:name)
|
340
|
+
category.entries.collect(&:name)
|
341
|
+
end
|
342
|
+
Bullet::Association.should be_has_unpreload_associations
|
343
|
+
end
|
344
|
+
|
345
|
+
it "should detect unused with category => [posts, entries]" do
|
346
|
+
Category.find(:all, :include => [:posts, :entries]).collect(&:name)
|
347
|
+
Bullet::Association.check_unused_preload_associations
|
348
|
+
Bullet::Association.should be_has_unused_preload_associations
|
349
|
+
end
|
350
|
+
|
351
|
+
it "should detect unused preload with category => entries, but no category => posts" do
|
352
|
+
Category.find(:all, :include => [:posts, :entries]).each do |category|
|
353
|
+
category.posts.collect(&:name)
|
354
|
+
end
|
355
|
+
Bullet::Association.check_unused_preload_associations
|
356
|
+
Bullet::Association.should be_has_unused_preload_associations
|
357
|
+
end
|
358
|
+
|
359
|
+
it "should detect no unused preload" do
|
360
|
+
Category.find(:all).each do |category|
|
361
|
+
category.posts.collect(&:name)
|
362
|
+
category.entries.collect(&:name)
|
363
|
+
end
|
364
|
+
Bullet::Association.check_unused_preload_associations
|
365
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
context "no preload" do
|
370
|
+
it "should no preload only display only one post => comment" do
|
371
|
+
Post.find(:all, :include => :comments).each do |post|
|
372
|
+
post.comments.first.name
|
373
|
+
end
|
374
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
375
|
+
end
|
376
|
+
|
377
|
+
it "should no preload only one post => commnets" do
|
378
|
+
Post.first.comments.collect(&:name)
|
379
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
context "named_scope for_category_name" do
|
384
|
+
it "should detect preload with post => category" do
|
385
|
+
Post.in_category_name('first').all.each do |post|
|
386
|
+
post.category.name
|
387
|
+
end
|
388
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
389
|
+
end
|
390
|
+
|
391
|
+
it "should not be unused preload post => category" do
|
392
|
+
Post.in_category_name('first').all.collect(&:name)
|
393
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
394
|
+
Bullet::Association.check_unused_preload_associations
|
395
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
context "named_scope preload_posts" do
|
400
|
+
it "should no preload post => comments with named_scope" do
|
401
|
+
Post.preload_posts.each do |post|
|
402
|
+
post.comments.collect(&:name)
|
403
|
+
end
|
404
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
405
|
+
end
|
406
|
+
|
407
|
+
it "should unused preload with named_scope" do
|
408
|
+
Post.preload_posts.collect(&:name)
|
409
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
410
|
+
Bullet::Association.check_unused_preload_associations
|
411
|
+
Bullet::Association.should be_has_unused_preload_associations
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
context "no unused" do
|
416
|
+
it "should no unused only display only one post => comment" do
|
417
|
+
Post.find(:all, :include => :comments).each do |post|
|
418
|
+
i = 0
|
419
|
+
post.comments.each do |comment|
|
420
|
+
if i == 0
|
421
|
+
comment.name
|
422
|
+
else
|
423
|
+
i += 1
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
Bullet::Association.check_unused_preload_associations
|
428
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
context "belongs_to" do
|
433
|
+
it "should preload comments => post" do
|
434
|
+
Comment.find(:all).each do |comment|
|
435
|
+
comment.post.name
|
436
|
+
end
|
437
|
+
Bullet::Association.should be_has_unpreload_associations
|
438
|
+
end
|
439
|
+
|
440
|
+
it "should no preload comment => post" do
|
441
|
+
Comment.first.post.name
|
442
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
443
|
+
end
|
444
|
+
|
445
|
+
it "should no preload comments => post" do
|
446
|
+
Comment.find(:all, :include => :post).each do |comment|
|
447
|
+
comment.post.name
|
448
|
+
end
|
449
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
450
|
+
end
|
451
|
+
|
452
|
+
it "should detect no unused preload comments => post" do
|
453
|
+
Comment.find(:all).collect(&:name)
|
454
|
+
Bullet::Association.check_unused_preload_associations
|
455
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
456
|
+
end
|
457
|
+
|
458
|
+
it "should detect unused preload comments => post" do
|
459
|
+
Comment.find(:all, :include => :post).collect(&:name)
|
460
|
+
Bullet::Association.check_unused_preload_associations
|
461
|
+
Bullet::Association.should be_has_unused_preload_associations
|
462
|
+
end
|
463
|
+
|
464
|
+
it "should dectect no unused preload comments => post" do
|
465
|
+
Comment.find(:all).each do |comment|
|
466
|
+
comment.post.name
|
467
|
+
end
|
468
|
+
Bullet::Association.check_unused_preload_associations
|
469
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
470
|
+
end
|
471
|
+
|
472
|
+
it "should dectect no unused preload comments => post" do
|
473
|
+
Comment.find(:all, :include => :post).each do |comment|
|
474
|
+
comment.post.name
|
475
|
+
end
|
476
|
+
Bullet::Association.check_unused_preload_associations
|
477
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
describe Bullet::Association, 'has_and_belongs_to_many' do
|
483
|
+
|
484
|
+
include BulletTestHelper
|
485
|
+
def setup_db
|
486
|
+
ActiveRecord::Schema.define(:version => 1) do
|
487
|
+
create_table :students do |t|
|
488
|
+
t.column :name, :string
|
489
|
+
end
|
490
|
+
|
491
|
+
create_table :teachers do |t|
|
492
|
+
t.column :name, :string
|
493
|
+
end
|
494
|
+
|
495
|
+
create_table :students_teachers, :id => false do |t|
|
496
|
+
t.column :student_id, :integer
|
497
|
+
t.column :teacher_id, :integer
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
def teardown_db
|
503
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
504
|
+
ActiveRecord::Base.connection.drop_table(table)
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
class Student < ActiveRecord::Base
|
509
|
+
has_and_belongs_to_many :teachers
|
510
|
+
end
|
511
|
+
|
512
|
+
class Teacher < ActiveRecord::Base
|
513
|
+
has_and_belongs_to_many :students
|
514
|
+
end
|
515
|
+
|
516
|
+
before(:all) do
|
517
|
+
silence_logger { setup_db }
|
518
|
+
student1 = Student.create(:name => 'first')
|
519
|
+
student2 = Student.create(:name => 'second')
|
520
|
+
teacher1 = Teacher.create(:name => 'first')
|
521
|
+
teacher2 = Teacher.create(:name => 'second')
|
522
|
+
student1.teachers = [teacher1, teacher2]
|
523
|
+
student2.teachers = [teacher1, teacher2]
|
524
|
+
teacher1.students << student1
|
525
|
+
teacher2.students << student2
|
526
|
+
end
|
527
|
+
|
528
|
+
after(:all) do
|
529
|
+
teardown_db
|
530
|
+
end
|
531
|
+
|
532
|
+
before(:each) do
|
533
|
+
Bullet::Association.start_request
|
534
|
+
end
|
535
|
+
|
536
|
+
after(:each) do
|
537
|
+
Bullet::Association.end_request
|
538
|
+
end
|
539
|
+
|
540
|
+
it "should detect unpreload associations" do
|
541
|
+
Student.find(:all).each do |student|
|
542
|
+
student.teachers.collect(&:name)
|
543
|
+
end
|
544
|
+
Bullet::Association.should be_has_unpreload_associations
|
545
|
+
end
|
546
|
+
|
547
|
+
it "should detect no unpreload associations" do
|
548
|
+
Student.find(:all, :include => :teachers).each do |student|
|
549
|
+
student.teachers.collect(&:name)
|
550
|
+
end
|
551
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
552
|
+
end
|
553
|
+
|
554
|
+
it "should detect unused preload associations" do
|
555
|
+
Student.find(:all, :include => :teachers).collect(&:name)
|
556
|
+
Bullet::Association.check_unused_preload_associations
|
557
|
+
Bullet::Association.should be_has_unused_preload_associations
|
558
|
+
end
|
559
|
+
|
560
|
+
it "should detect no unused preload associations" do
|
561
|
+
Student.find(:all).collect(&:name)
|
562
|
+
Bullet::Association.check_unused_preload_associations
|
563
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
describe Bullet::Association, 'has_many :through' do
|
568
|
+
|
569
|
+
include BulletTestHelper
|
570
|
+
|
571
|
+
def setup_db
|
572
|
+
ActiveRecord::Schema.define(:version => 1) do
|
573
|
+
create_table :firms do |t|
|
574
|
+
t.column :name, :string
|
575
|
+
end
|
576
|
+
|
577
|
+
create_table :clients do |t|
|
578
|
+
t.column :name, :string
|
579
|
+
end
|
580
|
+
|
581
|
+
create_table :relations do |t|
|
582
|
+
t.column :firm_id, :integer
|
583
|
+
t.column :client_id, :integer
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
def teardown_db
|
589
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
590
|
+
ActiveRecord::Base.connection.drop_table(table)
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
class Firm < ActiveRecord::Base
|
595
|
+
has_many :relations
|
596
|
+
has_many :clients, :through => :relations
|
597
|
+
end
|
598
|
+
|
599
|
+
class Client < ActiveRecord::Base
|
600
|
+
has_many :relations
|
601
|
+
has_many :firms, :through => :relations
|
602
|
+
end
|
603
|
+
|
604
|
+
class Relation < ActiveRecord::Base
|
605
|
+
belongs_to :firm
|
606
|
+
belongs_to :client
|
607
|
+
end
|
608
|
+
|
609
|
+
before(:all) do
|
610
|
+
silence_logger { setup_db }
|
611
|
+
firm1 = Firm.create(:name => 'first')
|
612
|
+
firm2 = Firm.create(:name => 'second')
|
613
|
+
client1 = Client.create(:name => 'first')
|
614
|
+
client2 = Client.create(:name => 'second')
|
615
|
+
firm1.clients = [client1, client2]
|
616
|
+
firm2.clients = [client1, client2]
|
617
|
+
client1.firms << firm1
|
618
|
+
client2.firms << firm2
|
619
|
+
end
|
620
|
+
|
621
|
+
after(:all) do
|
622
|
+
teardown_db
|
623
|
+
end
|
624
|
+
|
625
|
+
before(:each) do
|
626
|
+
Bullet::Association.start_request
|
627
|
+
end
|
628
|
+
|
629
|
+
after(:each) do
|
630
|
+
Bullet::Association.end_request
|
631
|
+
end
|
632
|
+
|
633
|
+
it "should detect unpreload associations" do
|
634
|
+
Firm.find(:all).each do |firm|
|
635
|
+
firm.clients.collect(&:name)
|
636
|
+
end
|
637
|
+
Bullet::Association.should be_has_unpreload_associations
|
638
|
+
end
|
639
|
+
|
640
|
+
it "should detect no unpreload associations" do
|
641
|
+
Firm.find(:all, :include => :clients).each do |firm|
|
642
|
+
firm.clients.collect(&:name)
|
643
|
+
end
|
644
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
645
|
+
end
|
646
|
+
|
647
|
+
it "should detect no unused preload associations" do
|
648
|
+
Firm.find(:all).collect(&:name)
|
649
|
+
Bullet::Association.check_unused_preload_associations
|
650
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
651
|
+
end
|
652
|
+
|
653
|
+
it "should detect unused preload associations" do
|
654
|
+
Firm.find(:all, :include => :clients).collect(&:name)
|
655
|
+
Bullet::Association.check_unused_preload_associations
|
656
|
+
Bullet::Association.should be_has_unused_preload_associations
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
describe Bullet::Association, 'has_many :as' do
|
661
|
+
|
662
|
+
include BulletTestHelper
|
663
|
+
|
664
|
+
def setup_db
|
665
|
+
ActiveRecord::Schema.define(:version => 1) do
|
666
|
+
create_table :votes do |t|
|
667
|
+
t.column :vote, :integer
|
668
|
+
t.references :voteable, :polymorphic => true
|
669
|
+
end
|
670
|
+
|
671
|
+
create_table :users do |t|
|
672
|
+
t.column :name, :string
|
673
|
+
end
|
674
|
+
|
675
|
+
create_table :pets do |t|
|
676
|
+
t.column :name, :string
|
677
|
+
t.column :user_id, :integer
|
678
|
+
end
|
679
|
+
|
680
|
+
create_table :news do |t|
|
681
|
+
t.column :name, :string
|
682
|
+
end
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
def teardown_db
|
687
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
688
|
+
ActiveRecord::Base.connection.drop_table(table)
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
class Vote < ActiveRecord::Base
|
693
|
+
belongs_to :voteable, :polymorphic => true
|
694
|
+
end
|
695
|
+
|
696
|
+
class User < ActiveRecord::Base
|
697
|
+
has_many :votes, :as => :voteable
|
698
|
+
has_many :pets
|
699
|
+
end
|
700
|
+
|
701
|
+
class Pet < ActiveRecord::Base
|
702
|
+
belongs_to :user
|
703
|
+
end
|
704
|
+
|
705
|
+
class News < ActiveRecord::Base
|
706
|
+
has_many :votes, :as => :voteable
|
707
|
+
end
|
708
|
+
|
709
|
+
before(:all) do
|
710
|
+
silence_logger { setup_db }
|
711
|
+
user1 = User.create(:name => 'first')
|
712
|
+
user2 = User.create(:name => 'second')
|
713
|
+
user3 = User.create(:name => 'third')
|
714
|
+
user4 = User.create(:name => 'fourth')
|
715
|
+
|
716
|
+
pet1 = User.create(:name => "dog")
|
717
|
+
pet2 = User.create(:name => "dog")
|
718
|
+
pet3 = User.create(:name => "cat")
|
719
|
+
pet4 = User.create(:name => "cat")
|
720
|
+
|
721
|
+
user1.votes << Vote.create(:vote => 10)
|
722
|
+
user1.votes << Vote.create(:vote => 20)
|
723
|
+
user2.votes << Vote.create(:vote => 10)
|
724
|
+
user2.votes << Vote.create(:vote => 20)
|
725
|
+
user3.votes << Vote.create(:vote => 10)
|
726
|
+
user3.votes << Vote.create(:vote => 20)
|
727
|
+
user4.votes << Vote.create(:vote => 10)
|
728
|
+
user4.votes << Vote.create(:vote => 20)
|
729
|
+
|
730
|
+
news1 = News.create(:name => 'first')
|
731
|
+
news2 = News.create(:name => 'second')
|
732
|
+
news1.votes << Vote.create(:vote => 10)
|
733
|
+
news1.votes << Vote.create(:vote => 20)
|
734
|
+
news2.votes << Vote.create(:vote => 10)
|
735
|
+
news2.votes << Vote.create(:vote => 20)
|
736
|
+
end
|
737
|
+
|
738
|
+
after(:all) do
|
739
|
+
teardown_db
|
740
|
+
end
|
741
|
+
|
742
|
+
before(:each) do
|
743
|
+
Bullet::Association.start_request
|
744
|
+
end
|
745
|
+
|
746
|
+
after(:each) do
|
747
|
+
Bullet::Association.end_request
|
748
|
+
end
|
749
|
+
|
750
|
+
# this happens only when a polymorphic association is included along with another table which is being referenced in the query
|
751
|
+
it "should not have unused preloaded associations with conditions" do
|
752
|
+
all_users = User.all(:include => :pets)
|
753
|
+
users_with_ten_votes = User.all(:include => :votes, :conditions => ["votes.vote = ?", 10])
|
754
|
+
users_without_ten_votes = User.all(:conditions => ["users.id not in (?)", users_with_ten_votes.collect(&:id)])
|
755
|
+
all_users.collect { |t| t.pets.collect(&:name) }
|
756
|
+
Bullet::Association.check_unused_preload_associations
|
757
|
+
Bullet::Association.should_not be_unused_preload_associations_for(User, :pets)
|
758
|
+
Bullet::Association.should_not be_unused_preload_associations_for(User, :votes)
|
759
|
+
end
|
760
|
+
|
761
|
+
it "should detect unpreload associations" do
|
762
|
+
User.find(:all).each do |user|
|
763
|
+
user.votes.collect(&:vote)
|
764
|
+
end
|
765
|
+
Bullet::Association.should be_has_unpreload_associations
|
766
|
+
end
|
767
|
+
|
768
|
+
it "should detect no unpreload associations" do
|
769
|
+
User.find(:all, :include => :votes).each do |user|
|
770
|
+
user.votes.collect(&:vote)
|
771
|
+
end
|
772
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
773
|
+
end
|
774
|
+
|
775
|
+
it "should detect unpreload associations with voteable" do
|
776
|
+
Vote.find(:all).each do |vote|
|
777
|
+
vote.voteable.name
|
778
|
+
end
|
779
|
+
Bullet::Association.should be_has_unpreload_associations
|
780
|
+
end
|
781
|
+
|
782
|
+
it "should detect no unpreload associations with voteable" do
|
783
|
+
Vote.find(:all, :include => :voteable).each do |vote|
|
784
|
+
vote.voteable.name
|
785
|
+
end
|
786
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
787
|
+
end
|
788
|
+
|
789
|
+
it "should detect no unused preload associations" do
|
790
|
+
User.find(:all).collect(&:name)
|
791
|
+
Bullet::Association.check_unused_preload_associations
|
792
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
793
|
+
end
|
794
|
+
|
795
|
+
it "should detect unused preload associations" do
|
796
|
+
User.find(:all, :include => :votes).collect(&:name)
|
797
|
+
Bullet::Association.check_unused_preload_associations
|
798
|
+
Bullet::Association.should be_has_unused_preload_associations
|
799
|
+
end
|
800
|
+
|
801
|
+
it "should detect no unused preload associations with voteable" do
|
802
|
+
Vote.find(:all).collect(&:vote)
|
803
|
+
Bullet::Association.check_unused_preload_associations
|
804
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
805
|
+
end
|
806
|
+
|
807
|
+
it "should detect unused preload associations with voteable" do
|
808
|
+
Vote.find(:all, :include => :voteable).collect(&:vote)
|
809
|
+
Bullet::Association.check_unused_preload_associations
|
810
|
+
Bullet::Association.should be_has_unused_preload_associations
|
811
|
+
end
|
812
|
+
end
|
813
|
+
|
814
|
+
describe Bullet::Association, "has_one" do
|
815
|
+
|
816
|
+
include BulletTestHelper
|
817
|
+
|
818
|
+
def setup_db
|
819
|
+
ActiveRecord::Schema.define(:version => 1) do
|
820
|
+
create_table :companies do |t|
|
821
|
+
t.column :name, :string
|
822
|
+
end
|
823
|
+
|
824
|
+
create_table :addresses do |t|
|
825
|
+
t.column :name, :string
|
826
|
+
t.column :company_id, :integer
|
827
|
+
end
|
828
|
+
end
|
829
|
+
end
|
830
|
+
|
831
|
+
def teardown_db
|
832
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
833
|
+
ActiveRecord::Base.connection.drop_table(table)
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
class Company < ActiveRecord::Base
|
838
|
+
has_one :address
|
839
|
+
end
|
840
|
+
|
841
|
+
class Address < ActiveRecord::Base
|
842
|
+
belongs_to :company
|
843
|
+
end
|
844
|
+
|
845
|
+
before(:all) do
|
846
|
+
silence_logger { setup_db }
|
847
|
+
|
848
|
+
company1 = Company.create(:name => 'first')
|
849
|
+
company2 = Company.create(:name => 'second')
|
850
|
+
|
851
|
+
Address.create(:name => 'first', :company => company1)
|
852
|
+
Address.create(:name => 'second', :company => company2)
|
853
|
+
end
|
854
|
+
|
855
|
+
after(:all) do
|
856
|
+
teardown_db
|
857
|
+
end
|
858
|
+
|
859
|
+
before(:each) do
|
860
|
+
Bullet::Association.start_request
|
861
|
+
end
|
862
|
+
|
863
|
+
after(:each) do
|
864
|
+
Bullet::Association.end_request
|
865
|
+
end
|
866
|
+
|
867
|
+
it "should detect unpreload association" do
|
868
|
+
Company.find(:all).each do |company|
|
869
|
+
company.address.name
|
870
|
+
end
|
871
|
+
Bullet::Association.should be_has_unpreload_associations
|
872
|
+
end
|
873
|
+
|
874
|
+
it "should detect no unpreload association" do
|
875
|
+
Company.find(:all, :include => :address).each do |company|
|
876
|
+
company.address.name
|
877
|
+
end
|
878
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
879
|
+
end
|
880
|
+
|
881
|
+
it "should detect no unused preload association" do
|
882
|
+
Company.find(:all).collect(&:name)
|
883
|
+
Bullet::Association.check_unused_preload_associations
|
884
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
885
|
+
end
|
886
|
+
|
887
|
+
it "should detect unused preload association" do
|
888
|
+
Company.find(:all, :include => :address).collect(&:name)
|
889
|
+
Bullet::Association.check_unused_preload_associations
|
890
|
+
Bullet::Association.should be_has_unused_preload_associations
|
891
|
+
end
|
892
|
+
end
|
893
|
+
|
894
|
+
describe Bullet::Association, "call one association that in possible objects" do
|
895
|
+
include BulletTestHelper
|
896
|
+
def setup_db
|
897
|
+
ActiveRecord::Schema.define(:version => 1) do
|
898
|
+
create_table :contacts do |t|
|
899
|
+
t.column :name, :string
|
900
|
+
end
|
901
|
+
|
902
|
+
create_table :emails do |t|
|
903
|
+
t.column :name, :string
|
904
|
+
t.column :contact_id, :integer
|
905
|
+
end
|
906
|
+
end
|
907
|
+
end
|
908
|
+
|
909
|
+
def teardown_db
|
910
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
911
|
+
ActiveRecord::Base.connection.drop_table(table)
|
912
|
+
end
|
913
|
+
end
|
914
|
+
|
915
|
+
class Contact < ActiveRecord::Base
|
916
|
+
has_many :emails
|
917
|
+
end
|
918
|
+
|
919
|
+
class Email < ActiveRecord::Base
|
920
|
+
belongs_to :contact
|
921
|
+
end
|
922
|
+
|
923
|
+
before(:all) do
|
924
|
+
silence_logger { setup_db }
|
925
|
+
|
926
|
+
contact1 = Contact.create(:name => 'first')
|
927
|
+
contact2 = Contact.create(:name => 'second')
|
928
|
+
|
929
|
+
email1 = contact1.emails.create(:name => 'first')
|
930
|
+
email2 = contact1.emails.create(:name => 'second')
|
931
|
+
email3 = contact2.emails.create(:name => 'third')
|
932
|
+
email4 = contact2.emails.create(:name => 'fourth')
|
933
|
+
end
|
934
|
+
|
935
|
+
after(:all) do
|
936
|
+
teardown_db
|
937
|
+
end
|
938
|
+
|
939
|
+
before(:each) do
|
940
|
+
Bullet::Association.start_request
|
941
|
+
end
|
942
|
+
|
943
|
+
after(:each) do
|
944
|
+
Bullet::Association.end_request
|
945
|
+
end
|
946
|
+
|
947
|
+
it "should detect no unpreload association" do
|
948
|
+
Contact.find(:all)
|
949
|
+
Contact.first.emails.collect(&:name)
|
950
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
describe Bullet::Association, "STI" do
|
955
|
+
include BulletTestHelper
|
956
|
+
def setup_db
|
957
|
+
ActiveRecord::Schema.define(:version => 1) do
|
958
|
+
create_table :documents do |t|
|
959
|
+
t.string :name
|
960
|
+
t.string :type
|
961
|
+
t.integer :parent_id
|
962
|
+
t.integer :author_id
|
963
|
+
end
|
964
|
+
|
965
|
+
create_table :authors do |t|
|
966
|
+
t.string :name
|
967
|
+
end
|
968
|
+
end
|
969
|
+
end
|
970
|
+
|
971
|
+
def teardown_db
|
972
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
973
|
+
ActiveRecord::Base.connection.drop_table(table)
|
974
|
+
end
|
975
|
+
end
|
976
|
+
|
977
|
+
class Document < ActiveRecord::Base
|
978
|
+
has_many :children, :class_name => "Document", :foreign_key => 'parent_id'
|
979
|
+
belongs_to :parent, :class_name => "Document", :foreign_key => 'parent_id'
|
980
|
+
belongs_to :author
|
981
|
+
end
|
982
|
+
|
983
|
+
class Page < Document
|
984
|
+
end
|
985
|
+
|
986
|
+
class Folder < Document
|
987
|
+
end
|
988
|
+
|
989
|
+
class Author < ActiveRecord::Base
|
990
|
+
has_many :documents
|
991
|
+
end
|
992
|
+
|
993
|
+
before(:all) do
|
994
|
+
silence_logger { setup_db }
|
995
|
+
author1 = Author.create(:name => 'author1')
|
996
|
+
author2 = Author.create(:name => 'author2')
|
997
|
+
folder1 = Folder.create(:name => 'folder1', :author_id => author1.id)
|
998
|
+
folder2 = Folder.create(:name => 'folder2', :author_id => author2.id)
|
999
|
+
page1 = Page.create(:name => 'page1', :parent_id => folder1.id, :author_id => author1.id)
|
1000
|
+
page2 = Page.create(:name => 'page2', :parent_id => folder1.id, :author_id => author1.id)
|
1001
|
+
page3 = Page.create(:name => 'page3', :parent_id => folder2.id, :author_id => author2.id)
|
1002
|
+
page4 = Page.create(:name => 'page4', :parent_id => folder2.id, :author_id => author2.id)
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
before(:each) do
|
1006
|
+
Bullet::Association.start_request
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
after(:each) do
|
1010
|
+
Bullet::Association.end_request
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
it "should detect unpreload associations" do
|
1014
|
+
Page.find(:all).each do |page|
|
1015
|
+
page.author.name
|
1016
|
+
end
|
1017
|
+
Bullet::Association.should be_has_unpreload_associations
|
1018
|
+
Bullet::Association.check_unused_preload_associations
|
1019
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
it "should not detect unpreload associations" do
|
1023
|
+
Page.find(:all, :include => :author).each do |page|
|
1024
|
+
page.author.name
|
1025
|
+
end
|
1026
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
1027
|
+
Bullet::Association.check_unused_preload_associations
|
1028
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
it "should detect unused preload associations" do
|
1032
|
+
Page.find(:all, :include => :author).collect(&:name)
|
1033
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
1034
|
+
Bullet::Association.check_unused_preload_associations
|
1035
|
+
Bullet::Association.should be_has_unused_preload_associations
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
it "should not detect unused preload associations" do
|
1039
|
+
Page.find(:all).collect(&:name)
|
1040
|
+
Bullet::Association.should_not be_has_unpreload_associations
|
1041
|
+
Bullet::Association.check_unused_preload_associations
|
1042
|
+
Bullet::Association.should_not be_has_unused_preload_associations
|
1043
|
+
end
|
1044
|
+
end
|