Topic: Polymorphic Relationship: has_one vs has_many

Greetings,
I'm working on a new RoR (Edge/1.2) application using the RESTful approach. I have a number of entities in my business model with addresses, so I have defined a polymorphic address class like so.

  class Address < ActiveRecord::Base
    belongs_to :addressable, :polymorphic => true
  end

Further, addresses use single-table inheritance to distinguish the type of address, such a Billing, Mailing, Street, etc.

The design question is this: does it make more sense to specify that an addressable entity such as a person has_many addresses, like so:

has_many :addresses :as => addressable, :dependent => :destroy

or to use something like:
has_one :mailing_address, :as => :addressable,
  :class_name => "MailingAddress", :dependent => :destroy

From the standpoint of RESTful best practices, the second approach seems more consistent in that I can have an addresses_controller manage address relationships for all addressable entities, but I'm unsure how to enforce a business rule like "a person must have one mailing address" whereas another addressable entity must have one street address.

Additionally, if I use the has_many approach, does it make sense to define methods in my models for getting and setting a specific type of address in order to enforce business rules (e.g., a person cannot have 2 mailing addresses) and simplify the retrieval of a specific address type in the view? Or is there a simpler way to do this without defining methods explicitly?

Any guidance or recommendations appreciated.

Thanks!

Re: Polymorphic Relationship: has_one vs has_many

I don't think STI is the best solution to this problem. Whether an address is Mailing, Billing, or Street depends more on how it is referenced than how it behaves. Removing STI also allows a given address to pass as all three if necessary - I don't know if you want this functionality, but I think it applies more often than not.

How do you distinguish the type of address without STI? You can use a foreign key in the addressable's table. For example, if a person has one mailing address, you can create a mailing_address_id column in the people table and set up the association like this:

class Person < ActiveRecord::Base
  has_many :addresses, :as => :addressable
  belongs_to :mailing_address, :class_name => 'Address', :foreign_key => 'mailing_address_id'
end

Railscasts - Free Ruby on Rails Screencasts

Re: Polymorphic Relationship: has_one vs has_many

Thanks for the quick response. I have a confession to make: I'm coming to RoR from 7 years of Java/J2EE development and will be the first to admit to attempting to carry those design principals over to RoR. I think in most cases this is a good thing, but in some cases that may mean I don't see the forest for the trees. Typing is a problem in any language, but I think in this case it is safe to say that a BillingAddress "is-a" Address, and thus a candidate for an inheritance relationship. That said, those who favor composition over inheritance would argue for an AddressType object to distinguish types. But in either case I would say that a person has one or more addresses I think.

With regard to the question at hand, it seems more flexible to allow an entity to have many addresses than to strictly define what types of addresses it can have. In either case, it sounds odd to me to say that a person belongs to an address rather than the other way around. (Particluary when it comes to cascading deletes.) Most business domain models will model a "Party" as having an address of a particular type for a specific duration (Coad, et.al.), and though that seemed overkill in my current application, I find it difficult to shed that influence.

Assuming I took the "person belongs-to address" approach, wouldn't that require explicit management of the person-address relationship rather than simply relying on active record? For example, I would have to destroy each of the addresses when a person is destroyed rather than just calling person.destroy, correct?

Or maybe I'm not understanding your example code correctly? Isn't the relationship being defined twice here? Once with has_many and once with belongs_to?

I apologize for thinking out loud here, but, as I said, I'm still working on reconciling my Java/O-O design experience with the Rails paradigm.

Thanks.

Re: Polymorphic Relationship: has_one vs has_many

jaldrich wrote:

I'm coming to RoR from 7 years of Java/J2EE development

You probably have more experience with this kind of thing than I do than. Take my suggestions with a grain of salt. wink


jaldrich wrote:

Typing is a problem in any language, but I think in this case it is safe to say that a BillingAddress "is-a" Address, and thus a candidate for an inheritance relationship.

What makes it a billing address however? That is dependent upon how it relates to other objects. Let's see if I can make it clearer with another example:

Sister is a Female, Female is a Human. You could do Human > Female > Sister subclassing. The Female subclass I would say is okay because Female is a constant state of the object - it never changes. However, Sister I would say is a bad subclass because it is dependent upon the relationship. She may be a Sister when compared to other siblings, but she may also be a Mother, Daughter, Aunt, etc when compared to others.

However, to extend the example further, I would say the Sister subclass is okay if your application only covers the scope of siblings. You could say the same thing with your application. If you never want a Billing address to also be a Street/Mailing address, and if you never need to change the type of the address, then subclassing may be the right approach.

jaldrich wrote:

In either case, it sounds odd to me to say that a person belongs to an address rather than the other way around.

Sometimes the has_many/belongs_to wording doesn't make sense, but don't let that stop you from making a good relationship. All "belongs_to" means is that the foreign key is in that table. It doesn't really mean the model "belongs to" the other model. Most of the time it works, but some cases like this it doesn't make as much sense, but it doesn't make the relationship any less correct.

jaldrich wrote:

Assuming I took the "person belongs-to address" approach, wouldn't that require explicit management of the person-address relationship rather than simply relying on active record? For example, I would have to destroy each of the addresses when a person is destroyed rather than just calling person.destroy, correct?

Hmm, destroying may be difficult to do. You can set up a has_many association in the Address model with a :dependent option, however, since it is a polymorphic association I don't know how well that will work. I would need to do some tests if I were to try that.

jaldrich wrote:

Or maybe I'm not understanding your example code correctly? Isn't the relationship being defined twice here? Once with has_many and once with belongs_to?

Correct, the relationship is defined twice, but in different contexts. In the has_many you are just defining which addresses that person has. In the belongs_to relationship you are defining which of those addresses you want to mail to.

From an interface perspective, you could have a list of a person's addresses with a radio button next to each one. Here the user can select which address he wants to be the mailing address. This can be done very easily by setting the id of the selected address as the mailing_address_id. If you do subclasses you would have to juggle around changing the type of the Address and handling errors of setting multiple addresses as the mailing address.

Railscasts - Free Ruby on Rails Screencasts

Re: Polymorphic Relationship: has_one vs has_many

Okay, this is starting to make sense. I guess the only other question I would have is how I would need to manage the two (belongs_to, has_many) relationships. If I have person.mailing_address = Address.new(params[:mailing_address]) will rails take care of adding the adddress or will this be a 2-step process something like so:

@mailing_address = Address.new(params[:mailing_address])
@person.mailing_address = @mailing_address
@person.addresses << @mailing_address

Thanks for your patience with a crusty old java developer!

BTW, I would say that the female in your inheritance example plays the role of sister--can't see sister extending female ;-)

Last edited by jaldrich (2006-12-05 15:52:17)

Re: Polymorphic Relationship: has_one vs has_many

jaldrich wrote:

Okay, this is starting to make sense. I guess the only other question I would have is how I would need to manage the two (belongs_to, has_many) relationships. If I have person.mailing_address = Address.new(params[:mailing_address]) will rails take care of adding the adddress or will this be a 2-step process something like so:

@mailing_address = Address.new(params[:mailing_address])
@person.mailing_address = @mailing_address
@person.addresses << @mailing_address

Thanks for your patience with a crusty old java developer!

To Rails the relationships are completely separate, so you would have to manage them both. However, I was assuming this would already be a two step process, where the addresses are created first and then one is selected to be a mailing address. Do you have the interface planned? That sometimes plays a role in decisions like this.

jaldrich wrote:

BTW, I would say that the female in your inheritance example plays the role of sister--can't see sister extending female ;-)

Exactly. But you can say "Sister is a Female". My example being "is a" isn't always a reason to subclass.

Railscasts - Free Ruby on Rails Screencasts

Re: Polymorphic Relationship: has_one vs has_many

I think I could just use a before_save filter to manage the relationship, so that shouldn't be problem.

I appreciate your help and guidance.

Re: Polymorphic Relationship: has_one vs has_many

Hi, i have a similar sort of situation.

I am working on an app which deals with information about Users, Posts(e.g. i need a toaster, My PC is not working etc), Cities, and Entities (e.g. company, restaurant, cafe etc). Now all of these models have pictures associated with them - A user can have many pictures, a post can contain many pictures, a city can have any pictures, and entities can have many pictures.

So now here i was thinking instead of having multiple tables for all these pictures why not create a single pictures table with the primary_key of user/city/post as foriegn key and type to identify which table it belongs to. hope the concept is clear - now i am coming accross this situation in many places of my app - i would like you to shed some light if it a good idea to go that way or implementing it the traditional way would be wiser and safer in the long run.

thanking in anticipation

radical vision fuels disruptive technologies

Re: Polymorphic Relationship: has_one vs has_many

I think that's an excellent approach dagger.  In your situation having pictures as a polymorphic association (where it stores both the type and the id of what it belongs to) is a good way to set it up.