Ruby on Rails : Has_One versus Belongs_To
Imagine you've got a small library of ContentTemplate objects. You're going to have instances of a Content object, and each of those pieces of Content will have a pointer to one ContentTemplate object. I suppose you'd call this a one-way many-to-one relationship. Many Content objects point to one ContentTemplate, but that one ContentTemplate does not need to know about its many Content objects. According to the traditional rules of composition you might think that Content has_one ContentTemplate, or even that ContentTemplate belongs_to Content. Both are incorrect. Let's look at why.
The second one first. If ContentTemplate belongs_to Content, then ContentTemplate will need to contain a key that says what single Content it belongs to. But ContentTemplates are used by many Content objects. So unless we want to get into a "has_and_belongs_to_many" relationship, this is not the answer. That's also wrong, since the Content object only needs to know about one ContentTemplate. It's not many to many. Also for this example our ContentTemplate does not need to know about the Content objects that use it.
So then the first is right - Content has_one ContentTemplate, yes? Nope. It appears from my experience that has_one implies a one:one relationship between the objects. That is, it assumes that when you create a new Content object, you're also going to create a new ContentTemplate object. Because the ContentTemplate object has to contain a content_id that points back to its parent. I found this concept articulated nicely at the very bottom of the wiki ForumExample: "With belongs_to, the table accepts responsibility for the foreign key. With has_one, the table expect the other table to hold it." So if Content has_one ContentTemplate, then ContentTemplate has to have the key. But as we already said, ContentTemplates are used by multiple Content objects. I don't want multiple instances of them, each pointing to its parent.
The answer turns out to be the combination of the two that might be counter-intuitive when you see it -- Content belongs_to ContentTemplate. Go back and look at how I described the problem, and you'll see that it works. With belongs_to, the table accepts responsibility for the foreign key. So Content has a content_template_id. And ContentTemplate doesn't need anything. I can point to it at will. Done.
Another way to think about this is to ask whether you're talking about creating objects or linking to pre-existing ones. If A has_one B, then when you create a new A you're probably going to be creating a new B as well. But if A belongs_to B, then you can point to a pre-existing B and hang yourself off of it. Say you've got a Person object that has_one Address. When you create a new Person, you're going to create a new Address to go with it. However, if you wanted to come back later and add another address (or change the current one) then you have to have something for that Address to belong to.
I have no idea if that made it easier to understand or not :). But I've just spent a hunk of the last 2 days trying to figure it out, and this seems to be the answer in this case, so I wanted to document it in case anybody else out there is having the same problem. ![]()