---
title: a compromise
teaser:
tags: web,rails
author: Jared Carroll
published_on: 2007-07-09
---

On a sidebar in the latest edition of [Agile Web
Development](http://www.amazon.com/Agile-Web-Development-Rails-2nd/dp/0977616630/ref=sr_1_7/190-2354092-9961534)
I noticed something.  It was a description of a class query method in
`ActiveRecord::Base` called `abstract_class?`.  Just what I was looking for.

Previously, I
[complained](https://thoughtbot.com/blog/whats-the-deal-with-rails-polymorphic-associations)
about not being able to do real behavior-based inheritance (the way inheritance
should be used) in Rails. To me `Student` and `Teacher` are not subclasses of
`Person` because they both have a `name`.  State means nothing, it should be
based on behavior.

Say in our app, we have users and companies.  Both of which can have any number
of addresses.  In other words, they're both addressable.

Let's model it out:

```ruby
class Addressable < ActiveRecord::Base
  has_many :addresses
end

class User < Addressable
end

class Company < Addressable
end

class Address < ActiveRecord::Base
  belongs_to :addressable
end
```

Now, using <abbr title="Single Table Inheritance">STI</abbr> we'd need at an
absolute minimum the following schema:

    addressables (id, type)
    addresses (id, addressable_id)

That is, our `User` and `Company` objects would both be stored in the
`addressables` table.

Let's say that the state about users and companies in our app is very different,
such that storing the union of all their attributes in 1 table is ugly,
inefficient and will result in a lot of nulls in each row.  Instead I want
separate tables for my users and companies.  However, you can't do that in Rails
when it comes to inheritance.

Now apparently, if this `ActiveRecord::Base` class query method named
`#abstract_class?` returns true Rails will never try to find a corresponding
table for it in the database.  That means Rails will assume its subclasses have
their own tables.

Let's rewrite the above example:

```ruby
class Addressable < ActiveRecord::Base
  has_many :addresses

  def self.abstract_class?
    true
  end
end

class User < Addressable
end

class Company < Addressable
end

class Address < ActiveRecord::Base
  belongs_to :addressable
end
```

Sweet.

No wait.

That doesn't work.  `Address` `belongs_to` addressable, when we say
`address.addressable` Rails will go looking for an `addressables` table and
fail.

So we're going to have to bust out polymorphic associations.

Rewrite:

```ruby
class Addressable < ActiveRecord::Base
  has_many :addresses, :as => :addressable

  def self.abstract_class?
    true
  end
end

class User < Addressable
end

class Company < Addressable
end

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

The schema:

     users (id, etc...)
     companies (id, etc...)
     addresses (id, addressable_id, addressable_type, etc...)

There we go.

Nice behavior-based inheritance.  We get to refer to users and companies as
`addressables` and we get to say:

```ruby
has_many :addresses, :as => :addressable
```

all in 1 place.

The alternative, and common Rails idiom when using polymorphic associations,
would not include the `Addressable` class, and be something along the lines of:

```ruby
class User < ActiveRecord::Base
  acts_as_addressable
end

class Company < ActiveRecord::Base
  acts_as_addressable
end

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

module ActsAsAddressable
  def acts_as_addressable
    self.class_eval do
      has_many :addresses, :as => :addressable
    end
  end
end

ActiveRecord::Base.extend ActsAsAddressable
```

With that `ActsAsAddressable` module defined as a plugin in 'vendor/plugins'.  I
don't like this style because of the need to put the `acts_as_addressable` in
each model.

And then you say, But that's more explicit, you look at the model, see the
`acts_as_addressable` declaration, and know right away its addressable.

Yes that's true but you can get the same effect in the previous solution because
the model subclasses `Addressable`.  There's no `acts_as_addressable`
declaration but by subclassing `Addressable` you can infer the same information.

I don't care much for the whole 'acts_as' naming convention either I'd rather
just use plain Ruby 'include' and rewrite the above as:

```ruby
class User < ActiveRecord::Base
  include Addressable
end

class Company < ActiveRecord::Base
  include Addressable
end

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

module Addressable
  def self.included(clazz)
    clazz.class_eval do
      has_many :addresses, :as => :addressable
    end
  end
end
```

And just put the `Addressable` module in 'lib/addressable.rb', no need for a
plugin.  The minute your `users` and `companies` become something more than just
`addressable`, such as `taggable`, you'll have to use either the `acts_as`
plugin style or just 'include' because Ruby only has single inheritance.  Then
the whole beauty of `ActiveRecord::Base#abstract_class?` is lost anyway.

However, `ActiveRecord::Base#abstract_class?`  does finally give Rails
developers the 'Concrete table inheritance' OR mapping pattern for inheritance
relationships.
