# Activerecord association design advice

**URL:** <https://www.ruby-forum.com/t/activerecord-association-design-advice/188853>\
**Category:** Rails\
**Created:** [May 19, 2010, 1:51pm UTC](https://www.ruby-forum.com/t/activerecord-association-design-advice/188853 "2010-05-19T13:51:16Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![ali](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@ali](https://www.ruby-forum.com/u/ali)\
**Post date:** [May 19, 2010, 1:51pm UTC](https://www.ruby-forum.com/t/activerecord-association-design-advice/188853/1 "2010-05-19T13:51:16Z")

</div>

Hi guys. So I have a few models: Concept, Entity, Dimension, Rating,  
User and Fact

1. Concepts can have many dimensions and many entities and many facts.
2. Concepts may share dimensions, but not entities or facts (so the  
Concept universities can share the Dimension quality but not the Fact  
num\_students.
3. A rating is determined by allowing a user to rate each dimension  
defined over the concept the entity belongs to.

I’m trying to design the relationships on paper before starting, and I  
thought I’d run it by you guys for suggestions, improvements, advice,  
etc (I’m quite new to rails and ruby).

def Dimension  
has\_and\_belongs\_to\_many :concepts

# for the ratings table

has\_many :ratings  
has\_many :entities, :through =\> :ratings  
has\_many :users, :through =\> :ratings  
def Fact  
def Entity

# for the ratings table

has\_many :ratings  
has\_many :dimensions, :through =\> :ratings  
has\_many :users, :through =\> :ratings  
def Concept  
has\_and\_belongs\_to\_many :dimensions  
has\_many :entities, :dependent =\> :destroy  
has\_many :facts, :dependent =\> :destroy  
def User

# for the ratings table

has\_many :ratings  
has\_many :dimensions, :through =\> :ratings  
has\_many :entities, :through =\> ratings  
def Rating

# the ratings table also has a value field when a user rates an

entity’s dimension  
belongs\_to :dimensions  
belongs\_to :users  
belongs\_to :entities

Thanks in advance

---

<div class="post-metadata">

**Author:** ![ali](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@ali](https://www.ruby-forum.com/u/ali)\
**Post date:** [May 19, 2010, 2:30pm UTC](https://www.ruby-forum.com/t/activerecord-association-design-advice/188853/2 "2010-05-19T14:30:30Z")

</div>

To me it looks like you are doing way too much abstraction here. With  
model names like Concept, Entity and Dimension it is going to be  
extremly hard for anybody else to wrap their heads around what exactly  
you are trying to design. At least I can’t do it, and hence I cant  
really give any advice either.

---

<div class="post-metadata">

**Author:** ![ali](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@ali](https://www.ruby-forum.com/u/ali)\
**Post date:** [May 20, 2010, 6:31am UTC](https://www.ruby-forum.com/t/activerecord-association-design-advice/188853/3 "2010-05-20T06:31:11Z")

</div>

Hi, ok if you replace Concept with Vehicle (ala tank, car, truck, plane,  
etc), Entity with Model (Z30, 911 turbo, F16, etc), Dimension with  
SubjectiveDimension (quality, comfort, etc) and Fact with  
FactualDimension  
(price, model\_year, max\_speed, etc) would it make more sense?

1. Vehicles have many models, subjective\_dimensions and  
factual\_dimensions
2. Vehicles may share subjective\_dimensions but not factual\_dimensions  
or or  
models
3. A rating is established by allowing users to rate all  
subjective\_dimensions of the vehicle that the model belongs to

So, I could rate an F16 by rating dimensions such as comfort\_level,  
sexiness, quality\_of\_landing and then rate a Porche 911 by rating  
dimensions  
such as comfort\_level, sexiness and steering\_response. Both of them (the  
F16  
and Porche) will have a factual\_dimension called price. These dimensions  
are  
defined over all objects inside a vehicle. The subjective\_dimensions can  
be  
shared between different entities (such as sexiness). They can be shared  
because they are subjective and relative differences don’t matter. With  
factual\_dimensions, what is considered a vehicle is not the same as a  
cheap  
car, that’s why they cannot be shared over vehicles.

So, changing the model files:

def User  
has\_many :ratings  
has\_many :subjective\_dimensions, :through =\> :ratings  
has\_many :models, :through =\> :ratings  
def Vehicle  
has\_and\_belongs\_to\_many :subjective\_dimensions  
has\_many :factual\_dimensions, :dependent =\> :destroy  
has\_many :models, :dependent =\> :destroy  
def Model  
belongs\_to :vehicles  
has\_many :ratings  
has\_many :subjective\_dimensions, :through =\> :ratings  
has\_many :users, :through =\> :ratings  
def SubjectiveDimension  
has\_and\_belongs\_to\_many :vehicles  
has\_many :ratings  
has\_many :users, :through =\> :ratings  
has\_many :models, :through =\> :ratings  
def FactualDimension  
belongs\_to :vehicles  
def Rating  
belongs\_to :user  
belongs\_to :model  
belongs\_to :subjective\_dimension

I hope that makes things a little bit clearer? There are a few other  
details  
which I would like to get feedback on as well, but I’ll leave that for  
after  
the above is taken care of.

---

<div class="post-metadata">

**Author:** ![ali](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@ali](https://www.ruby-forum.com/u/ali)\
**Post date:** [May 20, 2010, 10:58am UTC](https://www.ruby-forum.com/t/activerecord-association-design-advice/188853/4 "2010-05-20T10:58:40Z")

</div>

> Hi, ok if you replace (…) would it make more sense?  
> Absolutly!  
> For a while there I was wondering if you were setting out to program  
> the matrix.

Abstracting an objects attributes into it’s own table with a one-to-  
many (or many-to-many) association between the object and attributes  
should be the result of extreme requirement of flexibility an DRYness.  
There are alternatives that are also DRY and flexible, but easier to  
implement.

Are you familiar with single table inheritance? To me this looks like  
a case where it could be a good solution, if the number of vehicle  
types are fairly limited. When you have several entities that are  
almost the same, but not quite (I.E car, plane, boat), using single  
table inheritance is often a great way to reduce repetition. This will  
enable you to put all the attributes in one table, and decide which  
attributes a vehicle type should use through it’s type.

class Vehicle \< ActiveRecord::Base  
has\_many :models  
has\_many :ratings  
end

Class Car \< Vehicle

Class Plane \< Vehicle

Class Model  
belongs\_to :vehicle

What I am suggesting is that you create a super-class called Vehicle,  
that has sub-classes for each vehicle type (car, plane, etc). Shared  
logic is put in the super-class, individual logic is put in the sub-  
class.

I assume subjective dimensions are always the result of a user rating  
a vehicle? What to do with rating and subjective dimensions depends on  
what you do with Vehicle and factual dimesions. If you decide to use  
single table inheritance for the latter then it makes sense to use it  
for the former as well. You can remove the subjective dimesions table,  
and instead have subjective dimensions as attributes on the ratings  
table, and have sub-classes of rating for each sub-class of vehicle so  
that you are able to decide which subjective dimensions should come  
into play for each vehicle type.

Looking at the design you suggest I can see that you are trying to  
make a system that is 100% flexible by being able to decide exactly  
what kind of attributes each individual object has. I myself have  
never tried to implement a design where I abstracted the attributes  
into its own table, having a one-to-many association between the  
object and its attributes, so I don’t have any first hand experience  
with this. I dont imagine it will be easy. I imagine many challenges  
will arise from the fact that attributes can be of different types  
(string, integer, boolean, float, etc). If you dont need to any  
searching or reporting on the attributes then they could all be stored  
as strings, however if you need these things then you need their  
types, and implementing the searching and reporting will be very  
complex. It is also hard to imagine a system that needs to be this  
flexible in data storage without also having complex searching and  
reporting requirements.

---

<div class="post-metadata">

**Author:** ![ali](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/8c91f0/32.png) [@ali](https://www.ruby-forum.com/u/ali)\
**Post date:** [May 20, 2010, 11:59pm UTC](https://www.ruby-forum.com/t/activerecord-association-design-advice/188853/5 "2010-05-20T23:59:41Z")

</div>

Heh, not the matrix. What I am programming though is a ratable ontology,  
so  
the initial email with Concept, Entity and Dimension is the real code  
and  
I’m afraid flexibility is one of my main concerns because the number of  
vehicles, models and dimensions are completely unknown. So, single table  
inheritance on the vehicles is out of the question for the final  
application, unless of course there is a way to define models at run  
time,  
maybe every time a user defines a new vehicle I can call the ruby  
generator  
or something and have it create a class and corresponding tables. That  
may  
be overkill though. Is there any examples of web applications  
programming  
themselves? Now that sounds like some fun.

Anyway, the end goal is the ratable ontology (thesis related). For the  
prototype I’m developing though, I could use inheritance. The prototype  
uses  
2 parent concepts and a few child ones (Drink and Food would be the  
parent  
concepts, and the child concepts are: Cocktail, Beer, Wine, NonAlcoholic  
for  
the former and Starter, Main and Dessert for the latter). So single  
table  
inheritance sounds good here.

Subjective dimensions are a result of a user deciding what gives an  
object  
value. So a user would go into the system and decide that, “ooh, I think  
the  
rate at which a window can be lowered and raised makes a difference for  
me  
when rating a car”, so then the user will define a new subjective  
dimension:  
window\_raise\_speed. The application will then attach that new subjective  
dimension to all the cars and allow all users of the system from that  
point  
on to rate a car over window\_raise\_speed.

The thing about subjective dimensions is that they are all ordinal  
values,  
so they are all represented by floats. The actual values don’t mean  
anything, but what they represent do (max\_value means window\_raise\_speed  
is  
‘perfect’, or ‘couldn’t ask for more’, hence the subjectivity). I see  
your  
point when it comes to factual dimensions though, because they are not  
all  
ordinal and could be of any type.

Really appreciate the feedback.  
Thanks!
