06 July, 2007

has_many_polymorphs and the open-closed principle

I like has_many_polymorphs. I would love it if only it obeyed the open-closed principle.

Let's say I have a PetOwner model, and I want it to have_many pets polymorphically.

has_many_polymorphs lets you do this:

class PetOwner < ActiveRecord::Base
  has_many_polymorphs :from => [:dogs, :cats, :fish]
  ...
end

But what if I later decide I want to add a Ferret class? In addition to

class Ferret < AbstractPet
  ...
end

I also have to change PetOwner:
class PetOwner < ActiveRecord::Base
  has_many_polymorphs :from => [:dogs, :cats, :fish, :ferrets]
  ...
end

It would be really lovely if has_many_polymorphs could just tell what has inherited from AbstractPet. There's no reason you can't do this (in fact, I did before I wrote this post), but there's a timing problem: all of the inherited classes have to load before PetOwner does. The has_many_polymorphs ... call only happens when PetOwner is first included, so all of those other classes have to have already registered themselves with AbstractPet (simply by inheriting from it) by then; unfortunately, there's no good way to guarantee class load order without major hacking at the environment.

Sometimes we just have to put up with not-the-best. Alas.