Saturday, November 10, 2007

Nested ActiveRecord Relationships and Validation Conundrum

I ran into a bit of a pickle earlier this week with some models and their relationships.

The Situation

* A partner has an account.

* An account has an address.

* Accounts do not require an address; it's optional.

* Partners do require an address.

The Problem

So how do I enforce the presence of an address for the account assigned to the partner?

My First Attempt

My first thought was to break the encapsulation and create a direct partner-to-address relationship. Then I came up with the clever hack of keeping the partner-address in sync with the account-address during assignment, so when you set the address for the partner, it would automatically set the account to the same address. But it just didn't sit right with me; it wasn't the typical Ruby on Rails elegance I had come to expect. So I reached out to my partner in crime (Jack Danger) and asked for his opinion.

A More Elegant Idea

Jack suggested a more elegant simplification of just validating the presence of the address from the partner level like so:
validates_presence_of :address

def address
account && account.address
end
Now that's the simplicity and elegance I've come to expect from a Ruby on Rails application.

A Possible Third

But Jack also took it a step further and suggested subclassing account and making address required, so we'd have two types of accounts, one with optional addresses and one with required addresses. That might be even less code and arguably more elegant, but my gut just tells me it's a little less of a hack than my original attempt and not quite as pure as his first suggestion.

Wrapping Up

I went with Jack's first suggestion and I'm satisfied with the results, but I'm curious to hear if anybody else has tackled the same, or similar, problem, and how they solved it.