Hi Nic,
Regular relational databases are not object-oriented, so yes,
thinking in terms of RDBMS structure and and object-oriented
language like Ruby at the same time can cause dizzyness, and
occasionally nausea. In the OO-world relationships are frequently
established with inheritance; in the RDBMS world they are established
with associations. There are some new-fangled object-oriented
database management systems coming on the market these days (OODBMS),
mostly for java, that make the mapping between objects in your app
and objects in the db straightforward. I still miss the fast, simple
object db in Frontier…
Like Dan said, there are a few ways of cutting the pie. One option
is to have separate tables for users vs. people. This would be a
good choice if there’s little overlap between the two tables. But
fetching from a join between users and people is an expensive process
(relative to fetching from a single table). So, if there’s a fair
bit of overlap in the attributes (name, age, hair_color, ss_number,
favorite_continental_philosopher, etc.) then it makes sense to
structure the db with single table inheritance.
How do you do that? Setting up single table inheritance in a db is
pretty common, the Type-of-Person < Person subclassing is perhaps the
most typical. You can probably get some info on this for your db of
choice pretty easily on-line. Typically, you just set up the db with
all the columns that you’ll need for all classes. This means there
will be many object “closer” to the parent class that won’t be used.
A person might only have a name and id, for example. But an angry
spear-fisherman native whose good with poison darts will use a lot
more attributes (mood, source_of_food, good_with_poison_darts, etc.).
So, you’ve got to make sure that the columns that aren’t used by
every class are nullable (i.e., don’t set the column to ‘not
null’). That’s the first thing to remember. The second thing
involves tracking in the non-object-oriented db table what class each
person-row falls under. So, just add a column called something like,
‘person_type’.
Even though you’ve only got one table in your db you want to set up
your class structure in rails so that you can make use of the
inheritance structure in your app. That just means you define your
model objects with the hierarchy that you want:
class Person < ActiveRecord::Base
end
class SpearFisherman < Person
end
class User < Person
end
class DODEmployee < Person
end
class AngrySpearFisherman <SpearFisherman
end
You can then create objects of any of the above classes and they’ll
have access to any of the attributes in the entire table. It’s up to
you, in your code, to make sure that the angry spear-fisherman
doesn’t get assigned a DOD clearance number … well, wasn’t there
that picture of Rumsfield… O.k., nevermind, you get the idea. You
can use that ‘person_type’ column to help keep track of what your
code should be doing to any otherwise unknown row it pulls from the
db.
A couple of last things: you can’t have two objects that have an
attribute with the same name but are supposed to be different, e.g,.
you can’t have a ‘fish’ column that represents the type of fish
speared for the fisherman (varchar) but the number (int) of fish
eaten at the DOD press dinner since, obviously, you can’t have one
column with different types. You can use that same column to
represent semantically different things (number of fish eaten by that
person vs. number of types of fish that person can identify) but
you’ll eventually confuse yourself if you do this.
Lastly, don’t name that ‘person_type’ column something like ‘type’
(or if you do, change the mapping from the Ruby class to the column
so that it’s something else) because that’s the name of a Ruby method.
Sheesh, I really rambled. Anyway, the Agile book covers this same
material pretty well in ch. 15, I think.
Best,
Russ