# Aggregation/composed model attribute

**URL:** <https://www.ruby-forum.com/t/aggregation-composed-model-attribute/95498>\
**Category:** Rails\
**Created:** [December 6, 2005, 8:24pm UTC](https://www.ruby-forum.com/t/aggregation-composed-model-attribute/95498 "2005-12-06T20:24:37Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![alien8](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ecccb3/32.png) [@alien8](https://www.ruby-forum.com/u/alien8)\
**Post date:** [December 6, 2005, 8:24pm UTC](https://www.ruby-forum.com/t/aggregation-composed-model-attribute/95498/1 "2005-12-06T20:24:37Z")

</div>

First off, apologies about my previous empty post.

Also, apologies for the newbie nature of this post. I am new to rails  
and I’m working on a simple relational database to be administered  
and accessible to the public through rails. I have a question about  
aggregation as outlined in the pragprog “agile web development” book,  
around page 258 to 260. My example is nearly identical to the one  
used in the book. I have basically followed the example there to the  
letter, the only difference is that I want to aggregate fields from a  
model called Author rather than Customer, and one of the field names  
is different.

My question is simply this, once the Author model refers to the new  
Name model, how can I access the new :name attribute of instances of  
Author? I tried to do that in a view with the following code:

\<%=  
author[:name] %\> It doesn’t return an error, just doesn’t output  
anything. The book shows how to created a new instance of Customer  
with the aggregate Name object, but what about instances from a  
database record? Shouldn’t they have a :name attribute if they have  
all the attributes that it’s composed of?

The code I’ve used for Author and Name models is below. Thanks in  
advance for any info on where I’m going wrong.

\*\*\* app/models/author.rb \*\*\*  
class Author \< ActiveRecord::Base

has\_and\_belongs\_to\_many :books  
validates\_presence\_of :first\_name, :last\_name

# composed\_of declaration maps Author attributes to the Name model

object  
composed\_of :name,  
:class\_name =\> Name,  
:mapping =\>  
[[ :first\_name, :first],  
[:other\_name, :other],  
[:last\_name, :last]  
]  
end

* * *

\*\*\* app/models/name.rb \*\*\*

# Class defines the Name object, aggregation of attirbutes of Author

# object.

class Name  
attr\_reader :first, :other, :last

def initialize(first, other, last)  
@first = first  
@other = other  
@last = last  
end

def to\_s  
[@first, @other, @last].compact.join(" ")  
end  
end

---

<div class="post-metadata">

**Author:** ![alien8](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ecccb3/32.png) [@alien8](https://www.ruby-forum.com/u/alien8)\
**Post date:** [December 6, 2005, 9:50pm UTC](https://www.ruby-forum.com/t/aggregation-composed-model-attribute/95498/2 "2005-12-06T21:50:25Z")

</div>

Use: \<%= author.name %\> then check out page 203.

Cody

On 12/6/05, Alien8 Recordings [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> is different.  
> The code I’ve used for Author and Name models is below. Thanks in  
> composed\_of :name,
> 
> # Class defines the Name object, aggregation of attirbutes of Author
> 
> def to\_s  
> [@first, @other, @last].compact.join(" ")  
> end  
> end
> 
> * * *
> 
> Rails mailing list  
> removed\_email\_address@domain.invalid  
> [http://lists.rubyonrails.org/mailman/listinfo/rails](http://lists.rubyonrails.org/mailman/listinfo/rails)

–  
[http://www.codyfauser.com](http://www.codyfauser.com)

---

<div class="post-metadata">

**Author:** ![alien8](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ecccb3/32.png) [@alien8](https://www.ruby-forum.com/u/alien8)\
**Post date:** [December 6, 2005, 11:08pm UTC](https://www.ruby-forum.com/t/aggregation-composed-model-attribute/95498/3 "2005-12-06T23:08:05Z")

</div>

Hey Cody,

Sorry, just one more question. I see that you can’t use symbols to  
access model attributes that are aggregated, but what does one do in  
the case when one wants to pass them to a method that requires  
symbols, such as:  
auto\_complete\_for :post, :title

Thanks,  
Sean

On 6-Dec-05, at 3:47 PM, Cody F. wrote:

> > and I’m working on a simple relational database to be administered  
> > Author? I tried to do that in a view with the following code: \<%=  
> > class Author \< ActiveRecord::Base  
> > [:other\_name, :other],
> 
> * * *
> 
> Rails mailing list  
> removed\_email\_address@domain.invalid  
> [http://lists.rubyonrails.org/mailman/listinfo/rails](http://lists.rubyonrails.org/mailman/listinfo/rails)

* * *

ALIEN8 RECORDINGS  
P.O. BOX 666, STATION R  
MONTREAL, QC  
CANADA, H2S 3L1

[http://www.alien8recordings.com](http://www.alien8recordings.com)

---

<div class="post-metadata">

**Author:** ![alien8](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ecccb3/32.png) [@alien8](https://www.ruby-forum.com/u/alien8)\
**Post date:** [December 7, 2005, 12:17am UTC](https://www.ruby-forum.com/t/aggregation-composed-model-attribute/95498/4 "2005-12-07T00:17:23Z")

</div>

Sean,

It all depends on what you’re doing. The reason auto\_complete\_for  
doesn’t work on the aggregate is because it builds the sql where  
conditions based on the symbol you pass in. Since there isn’t a  
‘name’ column in your table the query will fail. Click the ‘show  
source’ link on the rdocs for auto\_complete\_for for more details:  
[http://api.rubyonrails.com/classes/ActionController/Macros/AutoComplete/ClassMethods.html#M000032](http://api.rubyonrails.com/classes/ActionController/Macros/AutoComplete/ClassMethods.html#M000032)

Depending on your circumstances you could still access the attributes  
author.first\_name author.last\_name. Otherwise, in the case of  
autocomplete you can check out Thomas F.’ fantastic demos at  
[http://demo.script.aculo.us/](http://demo.script.aculo.us/), which show a customized autocomplete in  
action.

Cody

On 12/6/05, Alien8 Recordings [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > My question is simply this, once the Author model refers to the new
> > > 
> > > ```
> > > :mapping =>
> > > 
> > > ```
> > > 
> > > class Name  
> > > end  
> > > –  
> > > P.O. BOX 666, STATION R  
> > > MONTREAL, QC  
> > > CANADA, H2S 3L1
> 
> [http://www.alien8recordings.com](http://www.alien8recordings.com)
> 
> * * *
> 
> Rails mailing list  
> removed\_email\_address@domain.invalid  
> [http://lists.rubyonrails.org/mailman/listinfo/rails](http://lists.rubyonrails.org/mailman/listinfo/rails)

–  
[http://www.codyfauser.com](http://www.codyfauser.com)

---

<div class="post-metadata">

**Author:** ![alien8](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ecccb3/32.png) [@alien8](https://www.ruby-forum.com/u/alien8)\
**Post date:** [December 10, 2005, 7:16am UTC](https://www.ruby-forum.com/t/aggregation-composed-model-attribute/95498/5 "2005-12-10T07:16:30Z")

</div>

Sean,

For autocompleting names I usually cheat and create a full\_name  
attribute for the object. Then I create a before\_save callback that  
creates the full name from the first and last name. I am sacrificing  
the extra storage space for convenience. I find it is usually easier  
to bend your ideals to match Rails than the other way around.

class Person \< ActiveRecord::Base  
validates\_presence\_of :first\_name, :last\_name  
before\_save :generate\_full\_name

composed\_of :name,  
:mapping =\> [[ :first\_name, :first], [ :last\_name, :last  
] ]

def self.find\_by\_name(name)  
self.find\_all\_by\_first\_name\_and\_last\_name(name.first, name.last)  
end

private  
def generate\_full\_name  
self.full\_name = self.first\_name + " " + self.last\_name  
end  
end

class Name  
attr\_reader :first, :last

def initialize(first, last)  
@first, @last = first, last  
end

def last\_first  
“#@last, #@first”  
end  
end

This way you can keep all of your methods that are specific to names,  
like last\_first, in the Name class and use them for display purposes,  
but you can still conveniently autocomplete forms. There is some  
duplication, but I don’t think it really matters in the long run.

There are also dynamically generated finders for your attributes.  
These methods are automatically available for the model I’ve created  
above (and more):

Person.find\_by\_first\_name\_and\_last\_name(‘Cody’, ‘Fauser’)  
Person.find\_all\_by\_full\_name(‘Cody F.’)

And using the method defined above:  
Person.find\_by\_name(Name.new(‘Cody’, ‘Fauser’))

Hope this helps.

Cody

On 12/9/05, Alien8 Recordings [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> editing form with the resulting record. Since I have now learned that
> 
> > [Peak Obsession](http://api.rubyonrails.com/classes/ActionController/Macros/)  
> > Cody
> > 
> > > ```
> > > auto_complete_for :post, :title
> > > 
> > > ```
> > > 
> > > > Cody
> > > > 
> > > > > around page 258 to 260. My example is nearly identical to the one  
> > > > > instances of  
> > > > > advance for any info on where I’m going wrong.  
> > > > > composed\_of :name,
> > > > > 
> > > > > # Class defines the Name object, aggregation of attirbutes of
> > > 
> > > removed\_email\_address@domain.invalid  
> > > ALIEN8 RECORDINGS  
> > > P.O. BOX 666, STATION R  
> > > MONTREAL, QC  
> > > CANADA, H2S 3L1
> 
> [http://www.alien8recordings.com](http://www.alien8recordings.com)

–  
[http://www.codyfauser.com](http://www.codyfauser.com)

---

<div class="post-metadata">

**Author:** ![alien8](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/ecccb3/32.png) [@alien8](https://www.ruby-forum.com/u/alien8)\
**Post date:** [December 10, 2005, 4:04am UTC](https://www.ruby-forum.com/t/aggregation-composed-model-attribute/95498/6 "2005-12-10T04:04:53Z")

</div>

Hey Cody,

Thanks for yet more help on this issue (I’ve been working on other  
things in the last few days).

I was able to get a custom auto\_complete for function working, but  
now I am starting to wonder if creating an attribute by aggregation  
was really the way to go. When I submit the search form that I am  
using the auto\_complete\_for text field in I am calling a find() on  
the author model with a conditional statement and rendering an  
editing form with the resulting record. Since I have now learned that  
apparently all finds on columns other than id require sql (the  
conditional statements) I guess I’m in the same position that led me  
to try the custom auto\_complete\_for function. So I guess now my  
question is: do you know a way to do a conditional find on an active  
record object, so that I can match to the aggregated Name attribute?  
If not, I wonder if there is any way to get the auto\_complete\_for  
text field to pass an id even while the author name is being displayed.

Thanks again,  
Sean

On 6-Dec-05, at 6:15 PM, Cody F. wrote:

> Depending on your circumstances you could still access the attributes
> 
> > Sean
> > 
> > > > First off, apologies about my previous empty post.  
> > > > letter, the only difference is that I want to aggregate fields  
> > > > author[:name] %\> It doesn’t return an error, just doesn’t  
> > > > class Author \< ActiveRecord::Base  
> > > > [[ :first\_name, :first],  
> > > > class Name  
> > > > end  
> > > > –  
> > > > P.O. BOX 666, STATION R
> 
> –  
> [http://www.codyfauser.com](http://www.codyfauser.com)

* * *

ALIEN8 RECORDINGS  
P.O. BOX 666, STATION R  
MONTREAL, QC  
CANADA, H2S 3L1

[http://www.alien8recordings.com](http://www.alien8recordings.com)
