activerecord 1.10.0 → 1.10.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +9 -0
- data/lib/active_record/associations.rb +28 -14
- data/lib/active_record/associations/association_proxy.rb +4 -0
- data/lib/active_record/associations/has_many_association.rb +7 -1
- data/rakefile +1 -1
- data/test/associations_go_eager_test.rb +8 -1
- data/test/fixtures/db_definitions/oci.sql +3 -3
- data/test/fixtures/post.rb +1 -1
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
*1.10.1* (20th April, 2005)
|
2
|
+
|
3
|
+
* Fixed frivilous database queries being triggered with eager loading on empty associations and other things
|
4
|
+
|
5
|
+
* Fixed order of loading in eager associations
|
6
|
+
|
7
|
+
* Fixed stray comma when using eager loading and ordering together from has_many associations #1143
|
8
|
+
|
9
|
+
|
1
10
|
*1.10.0* (19th April, 2005)
|
2
11
|
|
3
12
|
* Added eager loading of associations as a way to solve the N+1 problem more gracefully without piggy-back queries. Example:
|
@@ -121,7 +121,7 @@ module ActiveRecord
|
|
121
121
|
#
|
122
122
|
# Consider the following loop using the class above:
|
123
123
|
#
|
124
|
-
# for post in Post.find(:all
|
124
|
+
# for post in Post.find(:all)
|
125
125
|
# puts "Post: " + post.title
|
126
126
|
# puts "Written by: " + post.author.name
|
127
127
|
# puts "Last comment on: " + post.comments.first.created_on
|
@@ -129,20 +129,29 @@ module ActiveRecord
|
|
129
129
|
#
|
130
130
|
# To iterate over these one hundred posts, we'll generate 201 database queries. Let's first just optimize it for retrieving the author:
|
131
131
|
#
|
132
|
-
# for post in Post.find(:all, :
|
132
|
+
# for post in Post.find(:all, :include => :author)
|
133
133
|
#
|
134
134
|
# This references the name of the belongs_to association that also used the :author symbol, so the find will now weave in a join something
|
135
135
|
# like this: LEFT OUTER JOIN authors ON authors.id = posts.author_id. Doing so will cut down the number of queries from 201 to 101.
|
136
136
|
#
|
137
137
|
# We can improve upon the situation further by referencing both associations in the finder with:
|
138
138
|
#
|
139
|
-
# for post in Post.find(:all, :
|
139
|
+
# for post in Post.find(:all, :include => [ :author, :comments ])
|
140
140
|
#
|
141
141
|
# That'll add another join along the lines of: LEFT OUTER JOIN comments ON comments.post_id = posts.id. And we'll be down to 1 query.
|
142
142
|
# But that shouldn't fool you to think that you can pull out huge amounts of data with no performance penalty just because you've reduced
|
143
143
|
# the number of queries. The database still needs to send all the data to Active Record and it still needs to be processed. So its no
|
144
144
|
# catch-all for performance problems, but its a great way to cut down on the number of queries in a situation as the one described above.
|
145
145
|
#
|
146
|
+
# Please note that because eager loading is fetching both models and associations in the same grab, it doesn't make sense to use the
|
147
|
+
# :limit property and it will be ignored if attempted.
|
148
|
+
#
|
149
|
+
# Also have in mind that since the eager loading is pulling from multiple tables, you'll have to disambiguate any column references
|
150
|
+
# in both conditions and orders. So :order => "posts.id DESC" will work while :order => "id DESC" will not. This may require that
|
151
|
+
# you alter the :order and :conditions on the association definitions themselves.
|
152
|
+
#
|
153
|
+
# It's currently not possible to use eager loading on multiple associations from the same table.
|
154
|
+
#
|
146
155
|
# == Modules
|
147
156
|
#
|
148
157
|
# By default, associations will look for objects within the current module scope. Consider:
|
@@ -684,24 +693,28 @@ module ActiveRecord
|
|
684
693
|
primary_key_table = generate_primary_key_table(reflections, schema_abbreviations)
|
685
694
|
|
686
695
|
rows = select_all_rows(options, schema_abbreviations, reflections)
|
687
|
-
records = { }
|
696
|
+
records, records_in_order = { }, []
|
688
697
|
primary_key = primary_key_table[table_name]
|
689
698
|
|
690
699
|
for row in rows
|
691
700
|
id = row[primary_key]
|
692
|
-
records[id]
|
693
|
-
|
701
|
+
records_in_order << (records[id] = instantiate(extract_record(schema_abbreviations, table_name, row))) unless records[id]
|
702
|
+
record = records[id]
|
703
|
+
|
694
704
|
reflections.each do |reflection|
|
695
|
-
next unless row[primary_key_table[reflection.table_name]]
|
696
|
-
|
697
705
|
case reflection.macro
|
698
706
|
when :has_many, :has_and_belongs_to_many
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
707
|
+
collection = record.send(reflection.name)
|
708
|
+
collection.loaded
|
709
|
+
|
710
|
+
next unless row[primary_key_table[reflection.table_name]]
|
711
|
+
|
712
|
+
association = reflection.klass.send(:instantiate, extract_record(schema_abbreviations, reflection.table_name, row))
|
713
|
+
collection.target.push(association) unless collection.target.include?(association)
|
703
714
|
when :has_one, :belongs_to
|
704
|
-
|
715
|
+
next unless row[primary_key_table[reflection.table_name]]
|
716
|
+
|
717
|
+
record.send(
|
705
718
|
"#{reflection.name}=",
|
706
719
|
reflection.klass.send(:instantiate, extract_record(schema_abbreviations, reflection.table_name, row))
|
707
720
|
)
|
@@ -709,9 +722,10 @@ module ActiveRecord
|
|
709
722
|
end
|
710
723
|
end
|
711
724
|
|
712
|
-
return
|
725
|
+
return records_in_order
|
713
726
|
end
|
714
727
|
|
728
|
+
|
715
729
|
def reflect_on_included_associations(associations)
|
716
730
|
[ associations ].flatten.collect { |association| reflect_on_association(association) }
|
717
731
|
end
|
@@ -67,7 +67,13 @@ module ActiveRecord
|
|
67
67
|
end
|
68
68
|
else
|
69
69
|
options[:conditions] = @finder_sql + (options[:conditions] ? " AND #{options[:conditions]}" : "")
|
70
|
-
|
70
|
+
|
71
|
+
if options[:order] && @options[:order]
|
72
|
+
options[:order] = "#{options[:order]}, #{@options[:order]}"
|
73
|
+
elsif @options[:order]
|
74
|
+
options[:order] = @options[:order]
|
75
|
+
end
|
76
|
+
|
71
77
|
@association_class.find(args.size == 1 ? args.first : args, options)
|
72
78
|
end
|
73
79
|
end
|
data/rakefile
CHANGED
@@ -8,7 +8,7 @@ require 'rake/contrib/rubyforgepublisher'
|
|
8
8
|
|
9
9
|
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
10
10
|
PKG_NAME = 'activerecord'
|
11
|
-
PKG_VERSION = '1.10.
|
11
|
+
PKG_VERSION = '1.10.1' + PKG_BUILD
|
12
12
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
13
13
|
|
14
14
|
RELEASE_NAME = "REL #{PKG_VERSION}"
|
@@ -17,6 +17,13 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
17
17
|
assert post.comments.include?(@greetings)
|
18
18
|
end
|
19
19
|
|
20
|
+
def test_with_ordering
|
21
|
+
posts = Post.find(:all, :include => :comments, :order => "posts.id DESC")
|
22
|
+
assert_equal @authorless, posts[0]
|
23
|
+
assert_equal @thinking, posts[1]
|
24
|
+
assert_equal @welcome, posts[2]
|
25
|
+
end
|
26
|
+
|
20
27
|
def test_loading_with_multiple_associations
|
21
28
|
posts = Post.find(:all, :include => [ :comments, :author, :categories ], :order => "posts.id")
|
22
29
|
assert_equal 2, posts.first.comments.size
|
@@ -25,7 +32,7 @@ class EagerAssociationTest < Test::Unit::TestCase
|
|
25
32
|
end
|
26
33
|
|
27
34
|
def test_loading_from_an_association
|
28
|
-
posts = @david.posts.find(:all, :include => :comments)
|
35
|
+
posts = @david.posts.find(:all, :include => :comments, :order => "posts.id")
|
29
36
|
assert_equal 2, posts.first.comments.size
|
30
37
|
end
|
31
38
|
|
@@ -199,8 +199,8 @@ create table categories (
|
|
199
199
|
);
|
200
200
|
|
201
201
|
create table categories_posts (
|
202
|
-
category_id integer not null references
|
203
|
-
post_id
|
202
|
+
category_id integer not null references categories initially deferred disable,
|
203
|
+
post_id integer not null references posts initially deferred disable
|
204
204
|
);
|
205
205
|
|
206
206
|
create table fk_test_has_pk (
|
@@ -209,5 +209,5 @@ create table fk_test_has_pk (
|
|
209
209
|
|
210
210
|
create table fk_test_has_fk (
|
211
211
|
id integer not null primary key,
|
212
|
-
fk_id integer not null references fk_test_has_fk initially deferred disable
|
212
|
+
fk_id integer not null references fk_test_has_fk initially deferred disable
|
213
213
|
);
|
data/test/fixtures/post.rb
CHANGED
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.8
|
|
3
3
|
specification_version: 1
|
4
4
|
name: activerecord
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.10.
|
7
|
-
date: 2005-04-
|
6
|
+
version: 1.10.1
|
7
|
+
date: 2005-04-20
|
8
8
|
summary: Implements the ActiveRecord pattern for ORM.
|
9
9
|
require_paths:
|
10
10
|
- lib
|