views:

277

answers:

1

I have a model "Task" which will HABTM many "TaskTargets".

When it comes to TaskTargets however, I'm writing the base TaskTarget class which is abstract (as much as can be in Rails). TaskTarget will be subclassed by various different conceptualizations of anything that can be the target of a task. So say, software subsystem, customer site, bathroom, etc...

The design of the classes here is fairly straightforward, but where I'm hitting a snag is in how I will relate it all together and how I will have rails manipulate those relationships.

My first thought is that I will have a TaskTarget table which will contain the basic common fields (name, description...). It will then also have a polymorphic relationship out to a table specific to the type of data the implementing class wraps. This implies that the data for one instance of a class implementing TaskTarget will be found in two tables.

The second approach is to create a polymorphic HABTM relationship between Task and subclasses of TaskTarget which I thought I could reuse the table name TaskTarget for the join table.

Option #2 I suspect is the most robust, but maybe I'm missing something. Thanks for any help and of course I'm really just asking to make sure I get it done right, once!

A: 

I think the two approaches (easily) available to you in Rails are:

1) Single Table Inheritance: You create a single TaskTarget table that has every field that every subclass might want. You then also add a "type" field that stores the class name, and Rails will pretty much do the rest for you. See the ActiveRecord api docs for more info, especially the "Single Table Inheritance" section.

2) Concrete Table Inheritance: There is no table for the base TaskTarget class. Instead, simply create a table for each concrete class in your hierarchy with only the fields needed by that class.

The first option makes it easier to do things like "Show me all the TaskTargets, regardless of subclass," and results in fewer tables. It does make it a little harder to tell exactly what one subclass can do, as opposed to another, and if you have a lot of TaskTargets, I suppose eventually having them all in one table could be a performance concern.

The second option makes for a cleaner schema that is somewhat easier to read, and each class will work pretty much just like any normal ActiveRecord model. However, joining across all TaskTarget tables can be cumbersome, especially as you add more subclasses in the future. Implementing any necessary polymorphic associations may also involve some extra complexity.

Which option is better in your situation will depend on what operations you need to implement, and the characteristics of your data set.

John Hyland
I definitely don't like the single table approach. Although it encapsulates the relationship fully, I suspect that will become a nightmare in many different regards.I'm leaning towards my second solution with a polymorphic relationship between Task and the different TaskTargets. That appears to be the approach Rails is most fluent in.I'd still welcome any kind of discussion or other answers on this!Thanks!
Omega
Well, how complex a hierarchy are you anticipating? If it's going to be a relatively small set of classes with a lot of overlap in required fields, I think Single Table Inheritance can be the simpler way to go, since it means you don't have to mess with the polymorphic associations and Rails handles most of the tricky bits for you. On the other hand, if you think the number of subclasses might be very large, then yeah, the TaskTarget table could get out of hand.
John Hyland
I suspect the number of subclasses could grow. Their whole reason for existing is so that I can encapsulate pieces of data that aren't always common across the various targets of Tasks.
Omega
Hm. I'm wondering if there might not be a simpler way to approach this problem. What kind of different information are you planning on putting in these various subclasses? Is there a way you could simply have a single TaskTarget class with a polymorphic association to the target itself?
John Hyland
All Targets will have "Name", "Description" and a few other flags like "Public" and "Enabled".The subclasses will store things like relationships to addresses and phone numbers. The possibilities there are limitless, because the idea is that they are the narrowing down of each different type.Which is why I want to use a base class for the few common traits they share in common. Which is also what makes them able to show up in the same result sets.
Omega
Hm. So... every "thing" in your system could be the target of a task, and so you're making a parallel class hierarchy of TaskTarget classes?Is there any reason not to just store the name and description in the thing itself, rather than create this parallel hierarchy? Why have a TaskTarget class at all?
John Hyland