piggyback 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/README.markdown +25 -25
- data/Rakefile +1 -1
- data/piggyback.gemspec +1 -1
- metadata +1 -1
data/CHANGELOG
CHANGED
data/README.markdown
CHANGED
@@ -9,7 +9,7 @@ Piggybacking refers to the technique of dynamically including attributes from an
|
|
9
9
|
This is best illustrated in an example. Consider these models:
|
10
10
|
|
11
11
|
class Author < ActiveRecord::Base
|
12
|
-
has_many :
|
12
|
+
has_many :posts
|
13
13
|
end
|
14
14
|
|
15
15
|
class Post < ActiveRecord::Base
|
@@ -18,43 +18,43 @@ This is best illustrated in an example. Consider these models:
|
|
18
18
|
|
19
19
|
ActiveRecord supports piggybacking simply by joining the associated table and selecting columns from it:
|
20
20
|
|
21
|
-
|
21
|
+
post = Post.joins(:author).select('posts.*, author.name AS author_name').first
|
22
22
|
|
23
|
-
|
24
|
-
=> "Why piggybacking in ActiveRecord is flawed"
|
23
|
+
post.title
|
24
|
+
# => "Why piggybacking in ActiveRecord is flawed"
|
25
25
|
|
26
|
-
|
27
|
-
=> "Alec Smart"
|
26
|
+
post.author_name
|
27
|
+
# => "Alec Smart"
|
28
28
|
|
29
|
-
As you can see, the `name` attribute from `Author` is treated as if it were an attribute of `
|
29
|
+
As you can see, the `name` attribute from `Author` is treated as if it were an attribute of `Post`. ActiveRecord dynamically determines a model's attributes from the result set returned by the database. Every column in the result set becomes an attribute of the instantiated ActiveRecord objects. Whether the columns originate from the model's own or from a foreign table doesn't make a difference.
|
30
30
|
|
31
31
|
Or so it seems. Actually there is a drawback which becomes obvious when we select non-string columns:
|
32
32
|
|
33
|
-
|
33
|
+
post = Post.joins(:author).select('posts.*, author.birthday AS author_birthday, author.rating AS author_rating').first
|
34
34
|
|
35
|
-
|
36
|
-
=> "2011-03-01"
|
35
|
+
post.author_birthday
|
36
|
+
# => "2011-03-01"
|
37
37
|
|
38
|
-
|
39
|
-
=> "4.5"
|
38
|
+
post.author_rating
|
39
|
+
# => "4.5"
|
40
40
|
|
41
|
-
Any attributes originating from
|
41
|
+
Any attributes originating from the `authors` table are treated as strings instead of being automatically type-casted as we would expect. The database returns result sets as plain text and ActiveRecord needs to obtain type information separately from the table schema in order to do its type-casting magic. Unfortunately, a model only knows about the columns types in its own table, so type-casting doesn't work with columns selected from foreign tables.
|
42
42
|
|
43
|
-
We could work around this by defining attribute reader methods in the `Post` model that implicitly
|
43
|
+
We could work around this by defining attribute reader methods in the `Post` model that implicitly convert the values:
|
44
44
|
|
45
45
|
class Post < ActiveRecord::Base
|
46
|
-
|
46
|
+
belongs_to :author
|
47
47
|
|
48
48
|
def author_birthday
|
49
|
-
Date.parse(read_attribute(
|
49
|
+
Date.parse(read_attribute(:author_birthday))
|
50
50
|
end
|
51
51
|
|
52
52
|
def author_rating
|
53
|
-
read_attribute(
|
53
|
+
read_attribute(:author_rating).to_f
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
However this is tedious, error-prone and repetitive if you do it in many models. The type-casting code shown above isn't solid and would
|
57
|
+
However this is tedious, error-prone and repetitive if you do it in many models. The type-casting code shown above isn't solid and would quickly become more complex in a real-life application. In its current state it won't handle `nil` values properly, for example.
|
58
58
|
|
59
59
|
|
60
60
|
### Piggyback to the rescue!
|
@@ -71,13 +71,13 @@ You simply declare which association you want to piggyback and how the attribute
|
|
71
71
|
|
72
72
|
Now you can do the following:
|
73
73
|
|
74
|
-
|
74
|
+
post = Post.piggyback(:author).first
|
75
75
|
|
76
|
-
|
77
|
-
=> Tue, 01 Mar 2011
|
76
|
+
post.author_birthday
|
77
|
+
# => Tue, 01 Mar 2011
|
78
78
|
|
79
|
-
|
80
|
-
=> 4.5
|
79
|
+
post.author_rating
|
80
|
+
# => 4.5
|
81
81
|
|
82
82
|
The type-casting works with any type of attribute, even with serialized ones.
|
83
83
|
|
@@ -104,7 +104,7 @@ If you want to use an SQL-expression for selecting an attribute, Piggyback can a
|
|
104
104
|
piggybacks :author, :author_name => "authors.first_name || ' ' || authors.last_name"
|
105
105
|
end
|
106
106
|
|
107
|
-
|
108
|
-
=> "Donald Duck"
|
107
|
+
post.author_name
|
108
|
+
# => "Donald Duck"
|
109
109
|
|
110
110
|
In fact, every value you pass in as a string will be treated as raw SQL in the SELECT clause.
|
data/Rakefile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'echoe'
|
3
3
|
|
4
|
-
Echoe.new('piggyback', '0.2.
|
4
|
+
Echoe.new('piggyback', '0.2.3') do |p|
|
5
5
|
p.description = "Piggyback attributes from associated models with ActiveRecord"
|
6
6
|
p.url = "http://github.com/juni0r/piggyback"
|
7
7
|
p.author = "Andreas Korth"
|
data/piggyback.gemspec
CHANGED