Class Composition in Rails

I think it might be helpful to document some of my experience (re-)learning Rails, specifically how it compares to Cocoa and Core Data. One concept I just hit that seems a bit foreign to me is the Rails version of the term "composition" and the composed_of directive.

The basic idea is that you have a single database table which contains the data for two classes. One might be considered an "embedded" class. The example the O'Reilly Rails book uses is that of a Person with an Address. In that case, the people table looks like this

id
type
name
email
street_address
city
state
zip


I don't want to reproduce all of the code here because that's what the book is for, but the gist is that street address, city, state and zip are managed by an Address class, whereas the other fields belong to Person. All of the data goes into the same table, but you can't just say:

somePerson.city = "Sunnyvale"

You actually have to do one of these:

somePerson.address.city = "Sunnyvale"
somePerson.address_city = "Sunnyvale"


I'm guessing this is for performance and/or database design reasons, but I don't think you'd see this type of thing in Cocoa. The interface would be similar, but it would more likely be implemented via a to-one relationship. Rails can, of course, do that too, which to me seems much more natural.
Design Element
Class Composition in Rails
Posted Dec 24, 2006 — 4 comments below




 

labrat — Dec 24, 06 2862

I haven't tried this (on a composed class but it works for other habtm association stuff) but you should be able to use delegate.

Add something like this under the class header:

delegate :city, :to => :address

Check out this post.

Otherwise you can implement your own accessor method.

ssp — Dec 24, 06 2864

I'm not really sure I understand this properly: Does that mean you can't have several people using the _same_ address?

[Detour: This is actually one of my growing pet peeves with Apple's Address Book. As more and more of my friends are getting married and / or having children, the number of people in my address book keeps growing as I need one entry per person to keep track of all the birthdays. For those cases I'd love to be able to just link several people to the same address without having to re-enter it for each of them (well, actually I started just not entering addresses and phone numbers for all but one of them because I'm lazy but that's neither ideal nor convenient if you want to send a birthday card to the 'wrong' person).]

Scott Stevenson — Dec 25, 06 2865 Scotty the Leopard

Does that mean you can't have several people using the _same_ address

Each person has its own address data. So yes, you can. In terms of SQL, it's no different than if the address, city, state and zip were part of person itself.

The advantage of this seems to be that you have more flexibility in code with Address data being loaded as its own class. In other words, you can add methods to Address that might not make sense to add to Person. This is just guessing on my part. There might be a better explanation.

Michael Koziarski — Dec 25, 06 2871

Hi Scott,

I'd also implement 'address' with a one to one relationship, in fact I have quite regularly, I wouldn't consider using composed_of for an address 'best practise'.

I'd say the O'Reilly authors were simply struggling for a use case for composed_of. A less-strange case is for multiple currency support. You probably don't want to have a 'prices' table, so use some composition.

composed_of :price, :class_name => "Money", :mapping => [%w(price amount), %w(currency currency)]




 

Comments Temporarily Disabled

I had to temporarily disable comments due to spam. I'll re-enable them soon.





Copyright © Scott Stevenson 2004-2015