# Single Table Inheritance

**URL:** <https://www.ruby-forum.com/t/single-table-inheritance/67370>\
**Category:** Rails\
**Created:** [September 2, 2006, 11:57pm UTC](https://www.ruby-forum.com/t/single-table-inheritance/67370 "2006-09-02T23:57:16Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![lee](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/bc8723/32.png) [@lee](https://www.ruby-forum.com/u/lee)\
**Post date:** [September 2, 2006, 11:57pm UTC](https://www.ruby-forum.com/t/single-table-inheritance/67370/1 "2006-09-02T23:57:16Z")

</div>

I have been experimenting with Single Table Inheritance as described in  
the More Active Record chapter in Agile Development with Rails.

I have started with an object model with three classes x, y and z (for  
brevity), where y \< x and z \< y. (I will want to extend this model  
further to subclass y with other classes.)

I have created a table called x (plural) in the database with  
attributes for x, y and z and a type attribute.

I then built a default scaffold application for x and added the  
subclasses y and z in the model x.rb. Using ‘console (irb)’ the  
behaviour is as expected, that is,

z.create(…) - creates a row in the table x with the type = ‘z’ and  
the attributes of x, y, z set accordingly.

This is not the case however when I use the scaffold-generated ‘create’  
page. When using this to create rows in table x, the entered attributes  
(eg, x.a and z.b) are set correctly in the newly created table row but  
the ‘type’ is not set (to z). I assume I need to change either the  
controller or model to get the correct behaviour, and would appreciate  
some guidance as to how to approach this.

Thanks in advance.

---

<div class="post-metadata">

**Author:** ![lee](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/bc8723/32.png) [@lee](https://www.ruby-forum.com/u/lee)\
**Post date:** [September 4, 2006, 2:44pm UTC](https://www.ruby-forum.com/t/single-table-inheritance/67370/2 "2006-09-04T14:44:01Z")

</div>

\> (eg, x.a and z.b) are set correctly in the newly created table row but \> the 'type' is not set (to z). I assume I need to change either the \> controller or model to get the correct behaviour, and would appreciate \> some guidance as to how to approach this. \>

I am assuming you have a line X.new(params[:x]) in the  
scaffold-generated controller somewhere. The “type” field is set by AR  
based on the type of the instantiated model class.

You will need to write custom controller code that either  
conditionally instantiates one of x,y or z  
or create three separate controllers, if that is matches your business  
domain more closely.

Scaffolding is sometimes nice, but you will rewrite almost all of it  
anyway.

Cheers,  
Max

---

<div class="post-metadata">

**Author:** ![lee](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/bc8723/32.png) [@lee](https://www.ruby-forum.com/u/lee)\
**Post date:** [September 5, 2006, 3:34pm UTC](https://www.ruby-forum.com/t/single-table-inheritance/67370/3 "2006-09-05T15:34:42Z")

</div>

Max, thanks for taking time to respond.

I have parked STI for now - I did get it to work but wasn’t happy with  
the impurity of the model ie. all attributes belong to base class, too  
many NULLs in base table etc. I can see it’s value for certain class  
hierarchies but not the one I am working on - a number of z subclasses  
which inherit from a single y class which in turn inherits from a  
single x class, and where z subclasses may be very different from  
eachother.

The solution I now have in mind is the following:

1. One controller with a new() action that instantiates the base class  
(x) and correct subclasses (y,z) for the input form data (using a  
‘type’ selected in the UI)
2. Create action that saves x and thru table association (e.g. has one,  
belongs to) saves the appropriate subclasses (y,z).
3. Individual models - one for x and y, and one for each sub class z.

I hope this’ll work and is a sensible approach - further advice  
welcomed.

Thanks,

Lee.

---

<div class="post-metadata">

**Author:** ![lee](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/bc8723/32.png) [@lee](https://www.ruby-forum.com/u/lee)\
**Post date:** [September 6, 2006, 12:49pm UTC](https://www.ruby-forum.com/t/single-table-inheritance/67370/4 "2006-09-06T12:49:43Z")

</div>

Thanks.

I think I understand 🙂

Does this mean the STI database table for the base class (say ‘x’ where  
‘y’ \< ‘x’) does not need to have columns for attributes of ‘y’ or other  
subclasses?

For example,

def class X  
attr\_writer :name  
end  
def class Y \< X  
attr\_write :number  
end

Using STI, define table for X with columns id, name, type and ‘YAML  
container’.

Create instance of Y and before\_save of X, encode Y (and thus X)  
attributes into ‘YAML container’

On find, use ‘type’ to YAMLise ‘YAML container’ into appropriate object  
e.g. Y (but could be other sub classes). Use this object, ignoring  
object X.

What is meant by a key handler?

---

<div class="post-metadata">

**Author:** ![lee](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/bc8723/32.png) [@lee](https://www.ruby-forum.com/u/lee)\
**Post date:** [September 5, 2006, 5:21pm UTC](https://www.ruby-forum.com/t/single-table-inheritance/67370/5 "2006-09-05T17:21:03Z")

</div>

On 9/5/06, Lee [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> welcomed.
> 
> Thanks,
> 
> Lee.

(sorry if this ends up being a double-post, my first post was refused)

One thing I like to do in situations where the sub-types only require  
different attributes is use STI and encode attributes/content in YAML  
in a before\_save. Then in after\_find you can hook a method to YAMLize  
the in-record YAML and build up a nice model.my\_attributes.key handler  
for it, and refer to the attributes in that way from your sub-classes.

The technique is easiest to understand via example, and for that I  
recommend you take a look at the open-source tumblelog engine project  
called Ozimodo; specifically inspect how it uses YAML to define post  
types and handle related attributes (there’s no STI in this specific  
example, but you can combine the technique with STI if you insist).

## Regards,

Bosko M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
[http://www.crowdedweb.com/](http://www.crowdedweb.com/)

---

<div class="post-metadata">

**Author:** ![lee](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/bc8723/32.png) [@lee](https://www.ruby-forum.com/u/lee)\
**Post date:** [September 19, 2006, 8:40pm UTC](https://www.ruby-forum.com/t/single-table-inheritance/67370/6 "2006-09-19T20:40:52Z")

</div>

Yes, it means what you describe. Better yet, Rails can do this for you  
(look at ‘serialize’ for an attribute in the API docs). The technique  
I described however does some meta magic to also translate  
your\_attribute.some\_key to your\_attribute[:some\_key] which is what  
‘serialize’ likes (since the serialized attribute is turned into a hash  
when the record is read).

-Bosko
