Activerecord association design advice

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

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.

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.

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.

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!