Sunday, December 16, 2007

Fundamentals: When Associations Get Saved (with new parent and child models)

Summary: Use the “Auto-generated methods” on the new parent object to build new associated child objects to gain the benefits of less code, encapsulation and cascading saves.

For example, do this:

Rather than this:


With all the automagic and flexibility (i.e. multiple ways to do the same thing) Ruby on Rails provides, it’s easy to get confused with how the framework behaves and what the best practices are. But it is just as easily solved when you have a few rules of thumbs to follow. This is very true for ActiveRecord behaviour, specifically when saving associated records.

There is even a section dedicated to it in the Agile Web Development Book with Rails (Chapter 18, Section 7). The book looks at an existing object at one end of the association, and a new object at the other. But it does not discuss dealing with two new objects.

So let’s look at some examples how associations work. Consider the following models:

Simple stuff. For clarity sake, we will refer to the Account as the parent object, and the Address as the child object. We can consider the Address as the child object as it stores the id of the parent object. In this case the field account_id to identify the Account. So let’s create a an Account with an associated Address.

Example 1 (Recommended)

When we add a has_one relationship, a number of new methods are defined on the receiver (e.g. Account#build_address). This is true for all relationships, although the methods differ. See the ROR documentation for a complete list of Auto-generated methods.

The key observation here is, when you build a new child object via the parent object using the build method you do not need to explicitly save the child object, as the save cascades. An alternative way of doing this is:

Example 2

The first example, is preferable since it’s less code due to encapsulation.

If you assign a parent object to a child object:

Example 3

You will need to explicitly save the child object. But don’t save the parent object, because you will end up with this:

It’s always best to standardize the way you write code. When possible, when creating new objects that have an association use the following pattern:

The benefits are:

  • encapsulation, hiding the implementation of how an address is created
  • less code
  • cascading saves

Although I looked at the has_one/belongs_to association, this also works for other associations such as has_many.

For my next post, I will discuss how validating associations works in this context.

Please note this blog is no longer maintained. Please visit CivilCode Inc - Custom Software Development.