Generic SingleTable inheritance

Hi all,
I would like to discuss a design idea I have in mind with you, in order
to get critical feedback.

ActiveRecord supports single table inheritance(STI) “per se”, BUT you
must add all possible instance variables(properties) of all subclasses
to the “base table”(as columns). I would like to circumvent this
restriction.

Say we have a
class AbstractGenericThing < ActiveRecord:Base
has_many :properties
end
In order to support STI the abstract_generic_things-table must have a
:type column.
Next comes the Property class
class Property < ActiveRecord:Base
belongs_to :GenericObject
end
The properties table has the following columns
:key, :string
:value, :string
-> hence we have a simple key-value-pair table.

Now any class which subclasses AbstractGenericThing inherits the
properties-array. A subclass can have as many properties as it requires.
So far we can have concrete (sub)classes for our concrete domain objects
but the property handling is not yet “intuitive”.
Enter ‘method_missing’-hook

class AbstractGenericThing

all methods which are not defined are handled as

properties

def method_missing(methodname, *args)
methodnameStr = methodname.to_s
if (methodnameStr.include? “=”)
# it’s a setter!
# remove the trailing =
methodnameStr.chop!
return setProperty(methodnameStr, args[0])
else
# it’s a getter!
return getProperty(methodnameStr)
end
end

helper method for setting the given property

def setProperty(propertyName, value)
property = self.properties.find(:first, :conditions => [ “name = ?”,
propertyName])
if (property.nil?)
# Looks like the property does not yet exist.
# Create it and set the value…
property = Property.new(:name => propertyName, :value => value)
# add this new property to my properties
self.properties << property
# safe?
else
# change the property’s value
p “modifying property”
property.value = value
property.save
#self.safe
end
end

helper method for getting the value of the given property

def getProperty(propertyName)
# there should be(at most) one
property = properties.find(:first, :conditions => [ “name = ?”,
propertyName])
if (property.nil?)
return nil
else
return property.value
end
end
end

Now we can dynamically “add” properties to our conrete objects(classes).
E.g.:

class Person < AbstractGenericThing
end

person = Person.new
person.GivenName = “John”
person.Name = “Smith”
person.GivenName

John
person.Name

Smith

Persistence works as expected, hence I am inclined to go with this
design.
BEFORE I do I would like to hear what you think? What am I missing(apart
from the semantics I loose as all properties are stored as strings)?

Thanks for any critical input!
Clemens

On Sun, Jul 02, 2006 at 11:55:13AM +0200, Clemens W. wrote:
} Hi all,
} I would like to discuss a design idea I have in mind with you, in
order
} to get critical feedback.
}
} ActiveRecord supports single table inheritance(STI) “per se”, BUT you
} must add all possible instance variables(properties) of all subclasses
} to the “base table”(as columns). I would like to circumvent this
} restriction.
[…]
} Persistence works as expected, hence I am inclined to go with this
} design.
} BEFORE I do I would like to hear what you think? What am I
missing(apart
} from the semantics I loose as all properties are stored as strings)?

Please take a look at
http://redcorundum.blogspot.com/2006/07/ror-additional-attributes-with-sti.html

I’d been meaning to post about it for a while, and you got me to
actually
write it up.

} Thanks for any critical input!
} Clemens
–Greg

Gregory S. wrote:

On Sun, Jul 02, 2006 at 11:55:13AM +0200, Clemens W. wrote:
} Hi all,
} I would like to discuss a design idea I have in mind with you, in
order
} to get critical feedback.
}
} ActiveRecord supports single table inheritance(STI) “per se”, BUT you
} must add all possible instance variables(properties) of all subclasses
} to the “base table”(as columns). I would like to circumvent this
} restriction.
[…]
} Persistence works as expected, hence I am inclined to go with this
} design.
} BEFORE I do I would like to hear what you think? What am I
missing(apart
} from the semantics I loose as all properties are stored as strings)?

Please take a look at
http://redcorundum.blogspot.com/2006/07/ror-additional-attributes-with-sti.html

I’d been meaning to post about it for a while, and you got me to
actually
write it up.

} Thanks for any critical input!
} Clemens
–Greg

Dear Greg,
thanks for posting your thoughts about this issue. Your solution brings
in mainly two improvements over mine.

  1. Replacing ‘method_missing’ by meta prgramming(‘additional_attribute’)
    This is definitely an improvement. Not only in performance(which might
    not be an issue) but mainly due to explicitness. Though this approach is
    applicable for the non-serialize-solution too. Or am I wrong?

  2. Persisting properties/attributes with ActiveRecord’s serialize(yaml)
    If you are absolutely sure that the properties are not needed for any
    (Db-)lookup I agree that the serialze-approach is way better(performance
    and simplicity). In my case I might need a lookup some properties so I
    am not sure whether I should switch to serialize.

Regards
Clemens

Ashley M. wrote:

On Jul 02, 2006, at 10:55 am, Clemens W. wrote:

I would like to discuss a design idea I have in mind with you, in
order
to get critical feedback.

ActiveRecord supports single table inheritance(STI) “per se”, BUT you
must add all possible instance variables(properties) of all subclasses
to the “base table”(as columns). I would like to circumvent this
restriction.

Hi Clemens

I was going to reply to you earlier - I won’t offer any feed back
because it seems Greg has given you everything you need. What I’m
curious about, though, is why you brought this up in the context of
STI?

I first had my Db schema which had the properties table. Then I thought
it would be nice if I could still have concrete classes for my various
domain objects. I then came across STI in the AWDwR-book but didn’t want
to give up the “flexibility” in the Db schema. This lead me to my
proposal.

Right now I’m very interested in solving both the missing
information and inheritance problems. Your problem seems separate
from inheritance though,

As mentioned above I still want to have specific(concrete) classes for
my domain objects, but I do not yet know all properties these classes
will have AND I don’t want to change the Db-schema everytime a new
domain object(and/or) property for domain object comes up. Maybe I am
looking too much into the future(not really XP’ish, I know).

because your solution allows a class to have
any properties.
What was it that made you need these arbitrary
properties anyway?

see my answers above. Also note in my last post that I admit that Greg’s
declarative(meta-programming) approach is “better”. Greg’s approach is
less “arbitrary”, which is fine for my project, too.

Actually I’ve thought of one useful thing I can pass on. Our
company’s wiki runs on XWiki, and this has a very basic schema. What
they do is use one table per database type - I believe they are named
something like ‘xwikistrings’, ‘xwikiintegers’, ‘xwikibooleans’,
etc. This way you get the flexibility without losing the ability to
do things “SELECT values FROM properties WHERE value > 3” efficiently.

Ashley

At the moment I do not see any need for absolutely needing to know the
type of my properties.

I am really happy getting this kind of critical feedback. It makes me
rethink and maybe even reject my decision, which is ok in the beginning
of a project :wink:

Regards
Clemens

On Jul 02, 2006, at 10:55 am, Clemens W. wrote:

I would like to discuss a design idea I have in mind with you, in
order
to get critical feedback.

ActiveRecord supports single table inheritance(STI) “per se”, BUT you
must add all possible instance variables(properties) of all subclasses
to the “base table”(as columns). I would like to circumvent this
restriction.

Hi Clemens

I was going to reply to you earlier - I won’t offer any feed back
because it seems Greg has given you everything you need. What I’m
curious about, though, is why you brought this up in the context of
STI? Right now I’m very interested in solving both the missing
information and inheritance problems. Your problem seems separate
from inheritance though, because your solution allows a class to have
any properties. What was it that made you need these arbitrary
properties anyway?

Actually I’ve thought of one useful thing I can pass on. Our
company’s wiki runs on XWiki, and this has a very basic schema. What
they do is use one table per database type - I believe they are named
something like ‘xwikistrings’, ‘xwikiintegers’, ‘xwikibooleans’,
etc. This way you get the flexibility without losing the ability to
do things “SELECT values FROM properties WHERE value > 3” efficiently.

Ashley

As mentioned above I still want to have specific(concrete) classes for
my domain objects, but I do not yet know all properties these classes
will have

uhhuh…another ActiveRDF candidate. theres really a lot of reading out
there on the subject, but for starters, id try the ActiveRDF docs[3],
the pdf from Obie F. ‘Deep Integration of Ruby with Semantic Web
Ontologies’[2], and a page from the W3C (concepts and abstract
syntax)[1].

  1. http://www.w3.org/TR/2004/REC-rdf-concepts-20040210/
  2. http://gigaton.thoughtworks.net/~ofernand1/DeepIntegration.pdf
  3. http://activerdf.org/manual/manual.html

I am really happy getting this kind of critical feedback. It makes me
rethink and maybe even reject my decision

no!! go with your instincts. just figure out a way to make them happen…
c

Hi!

On Jul 2, 2006, at 12:21 PM, Clemens W. wrote:

subclasses
Please take a look at

applicable for the non-serialize-solution too. Or am I wrong?
Clemens
Clemens-

If you use ferret and acts_as_ferret for your db searches then you

can define a custom .to_doc method in your models that hints to
ferret how to index and search your serialized attributes. This lets
you use nice serialization for meta data and stuff that changes too
often to go in the db. And you still get full text and fuzzy text
search on these serialized attributes.

Cheers-
-Ezra

On Jul 02, 2006, at 10:30 pm, Clemens W. wrote:

I first had my Db schema which had the properties table. Then I
thought
it would be nice if I could still have concrete classes for my various
domain objects. I then came across STI in the AWDwR-book but didn’t
want
to give up the “flexibility” in the Db schema. This lead me to my
proposal.

Clemens

Is this an existing schema you’ve inherited, or just your first draft
at a new project?

As mentioned above I still want to have specific(concrete) classes for
my domain objects, but I do not yet know all properties these classes
will have AND I don’t want to change the Db-schema everytime a new
domain object(and/or) property for domain object comes up. Maybe I am
looking too much into the future(not really XP’ish, I know).

Obviously without going into the requirements of your project I can’t
say what would suit you best. But I approach database design as a
mapping of business (or personal) requirements to facts. So if I
have a business need (say a legal requirement) to store a date of
birth of (say) an employee, then in it goes, as a specific column.
Properties as rows rather than columns strike me as more useful for
lookups rather than general queries. IE it’s easy to get all the
properties of a given employee, but hard to write queries like “Find
all managers more than 10 years older than the youngest employee they
supervise” (or something less contrived). Because data tends to
outlive applications, I prefer to go with the design that facilitates
ad-hoc queries.

As for XP, have you tried continuous integration? I’ve never done it
with Ruby/Rails but I believe there’s a tool called DamageControl.
CI lets you change the database as much as you like and still have
absolute confidence it will work when you deploy live. Used with
Migrations it should give you XP flexibility with old-fashioned
stability. (I believe that database CI is as important as unit
testing.)

see my answers above. Also note in my last post that I admit that
Greg’s
declarative(meta-programming) approach is “better”. Greg’s approach is
less “arbitrary”, which is fine for my project, too.

I like that solution from the Ruby side, but not the database side.
If I was going to use this property-based idea, I’d marry the two,
and take your separate property table but use the explicit
“additional_attribute :foo, :bar” metaprogramming to create the Ruby
attributes.

Just for comparison, here’s a similar solution to a problem that
cropped up at work. I’ve only just convinced my boss to start using
Rails, and he set one of our developers on to this small project for
calculating online IT quotations. Basically, we want the available
components for a quote (eg photocopiers, phones, faxes, whatever they
want to sell) to be determined from the database, and have the GUI
driven by the records it finds. But we don’t want to have to
duplicate all that information in the model class either. So what I
suggested is to make a Calculation class that subclasses OpenStruct,
and add an “identifier” column into the component records that will
be the Ruby attribute name. The neat thing about that is that you
can use Rails’ block HTML form assignment to construct a whole model
class. Then the code looks something like this:

class Calc < OpenStruct
def calc
total = 0
if self.respond_to?(:num_photocopiers)
total += * self.num_photocopiers
end
total
end
end

In fact, simple cases like that could be done even more elegantly by
adding a boolean “simple” attribute to the database, that indicated
to the code it could do a simple PRICE * QTY calc - it’s only the
case where one item implicitly requires ordering one or more other
parts that you need to write extra calculation rules.

While it’s not completely database driven, it’s got us 50% of the way
there with VERY little coding at all. (I’m not sure the developer
gets how it works yet, but soon he will have an AHA! moment and join
the metaprogramming crowd!)

This of course is a different problem to yours but I thought I’d
share it for comparison.

At the moment I do not see any need for absolutely needing to know the
type of my properties.

What better reason for making sure you record them ;o) (See above
for my obsession with making ad-hoc queries as easy as possible).

I am really happy getting this kind of critical feedback. It makes me
rethink and maybe even reject my decision, which is ok in the
beginning
of a project :wink:

No probs. I don’t have much experience using Rails, but I’m ok with
Ruby and databases. I’ve seen, though, that mistakes in the database
generally stay there forever. Hopefully unit testing will make Rails
apps suffer less from this. I’ve seen really hideous things in
databases, and when I ask why we have a redundant column storing
inconsistent data with no key constraints defined on it, the answer
usually goes “no idea, but it works and who knows how many features
will break if we remove it”.

Ashley

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs