Multi Table Inheritance and Stack Overflow errors.

51 views
Skip to first unread message

Raklet

unread,
Jul 6, 2011, 1:51:32 AM7/6/11
to Hobo Users
I am trying to implement multi table inheritance using the CITIER gem
(https://github.com/peterhamilton/citier/), but I gather from a recipe
discussion on single table inheritance that you have to leave out
"hobo_model" when inheriting from a class other than
ActiveRecord::Base.

(See http://cookbook.hobocentral.net/recipes/64-single-table-inheritance-with-children

"class Agent < Profile # For STI

# Leave out the hobo_model line. Without it, there is no tab for
the class (e.g. Agent tab).
# With it, the ^(*&% thing overflows the stack when creating,
editing, etc.")


Is there anyway to work around this?

If there is, will hobo generate the correct form composed of fields
from separate but inherited models?

Bryan Larsen

unread,
Jul 6, 2011, 7:59:16 AM7/6/11
to hobo...@googlegroups.com
I think the important thing is that `hobo_model` only gets called
once. Typical usage is to use it in the base model, but it may work
if you don't use it in the base model and do use it in the child
model.

Stress on the 'may' though, I haven't tried it that way.

Bryan

> --
> You received this message because you are subscribed to the Google Groups "Hobo Users" group.
> To post to this group, send email to hobo...@googlegroups.com.
> To unsubscribe from this group, send email to hobousers+...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/hobousers?hl=en.
>
>

Matt Jones

unread,
Jul 6, 2011, 3:20:10 PM7/6/11
to hobo...@googlegroups.com

On Jul 6, 2011, at 1:51 AM, Raklet wrote:

> I am trying to implement multi table inheritance using the CITIER gem
> (https://github.com/peterhamilton/citier/), but I gather from a recipe
> discussion on single table inheritance that you have to leave out
> "hobo_model" when inheriting from a class other than
> ActiveRecord::Base.
>
> (See http://cookbook.hobocentral.net/recipes/64-single-table-inheritance-with-children
>
> "class Agent < Profile # For STI
>
> # Leave out the hobo_model line. Without it, there is no tab for
> the class (e.g. Agent tab).
> # With it, the ^(*&% thing overflows the stack when creating,
> editing, etc.")
>
>
> Is there anyway to work around this?

The actual issue referenced in that recipe is that hobo_model hooks into a number of ActiveRecord methods using alias_method_chain, so calling hobo_model on a subclass ends up creating a nasty loop. As Bryan already noted, one option is to put the declaration into subclasses rather than the base (this is likely to be what you want anyways - the base class in the CTI examples isn't really something one creates directly).

> If there is, will hobo generate the correct form composed of fields
> from separate but inherited models?

Depending on how thoroughly CITIER fakes out ActiveRecord, it *may* work. It's certainly not anything that's been attempted, though. Overall, Hobo writes very little bare SQL (and none, AFAIK, that actually updates data) so it shouldn't cause too many problems.

One issue you will run into is that Hobofields shares a single list of field_specs for each direct descendant of ActiveRecord::Base. This is the correct behavior for STI (where fields declared in a subclass need to end up in the parent table) but is wrong for CTI. Not that you're going to be using the migration generator anyways - it's certainly not going to generate the right migrations for this approach.

On a somewhat unrelated note, I'd think hard about exactly what's driving the need for CTI in your data model. I'm not saying it's something that's totally useless, but the arguments for it on the gem documentation aren't exactly convincing:

- "OMG STI makes many columns": and? RDBMSes are designed to store lots of data. This complaint smells an awful lot like premature optimization, making early design decisions based on some unknown future where your application somehow needs thousands of columns on a model.

- the implied claim that inheritance is the only way to model an is_a relation: put another way, the example proposed in the documentation seems to be pushing information into the class hierarchy that's not really relevant. For instance, a dictionary "is a" book - but does it really have any meaningful operations on it that aren't applicable to a book as well? This is highly dependent on the domain model, but in the case they show some sort of "category" mechanism would likely work just as well. This is an especially hazardous trap to fall into in Ruby, where the standard escape hatch of multiple inheritance isn't available...

Some alternatives I'd recommend considering before going down the CTI route:

- the other way to get common functionality in many places in Ruby without repeating it - mixins. For instance, there's no reason (if you really, really, really don't want to do STI) that you couldn't lift common functionality (even fields blocks) into a module that's included into each relevant class.

- if your design absolutely requires many disparate objects with widely divergent sets of attributes all shoehorned into a single collection, you may want to read up on NoSQL alternatives. MongoDB has gotten a lot of positive attention in the Rails community of late, and it solves the whole "STI has lots of NULL columns" problem entirely. There's no Hobo support for it yet, though.

Anyways, hope this helps. If you have more questions about data modeling, the list is pretty open to helping - sanitize as needed, of course. :)

--Matt Jones

Raklet

unread,
Jul 7, 2011, 11:38:44 PM7/7/11
to hobo...@googlegroups.com
I have read the arguments for and against CTI and STI.  There are strong feelings in both camps.  It almost strikes me as one of those "religion and politics" type topics.

Putting that aside, I wanted to see if I could get CTI (using CITIER) to work with hobo (if for no other reason than to see if it was possible), and I am happy to report that it does work!

Here is the quick scoop

My Classes

Asset < ActiveRecord::Base
Crop < Asset
Acreage < Asset
Machine < Asset

Asset is a model only because I don't need to interact with it.  The other classes have a model and controller.  Hobo does not see the child classes and create navigation tabs for them, but manually creating a link for them (localhost:3000/crops) works.  A single form is displayed that contains all of the attributes of both Asset and Crop.  All CRUD functions work properly.  Adding association relationships also work as expected.

If you are interested in hearing more about it or think that a recipe would be of value to the community in general, I would be glad to do a detailed write-up.

Regards,

Tyler

p.s.  Though it doesn't happy automatically, a little tweaking to the models makes them work with the hobo migration generator (tweaks have to be done and undone each time I want to run a new migration, but it only takes a few minutes.)



kungfukilt

unread,
May 2, 2012, 11:00:14 PM5/2/12
to hobo...@googlegroups.com
i would definitely be interested in your recipe, as i am embarking on this route and getting there, but seeing what you've done will likely save on the ol' trial and error route:) tia! ~daVe
Reply all
Reply to author
Forward
0 new messages