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!