Any ideas on how to model this?


I'm attempting to move beyond the Agile Web Dev w\Rails book and explore
writing some practice apps from scratch. I m attempting to model an
online t-shirt shop were customers can select from a variety of
different designs. Each design will be available in different colors
and each color will have different sizes. Also, I'd like to keep track
of the number of available shirts.

My most recent data modeling attempt consists of 3 tables and respective
1. designs - name, description, picture, price.
2. color - color, design_id
3. size - size, color_id

The model associations are:
design - has_many :colors, has_many :sizes
color - has_many :sizes, belongs_to :designs
size - belongs_to :color, :belongs_to :design

The relationships are not right. You can break them easily by creating
a color belonging_to one design, and a size belonging to the same
color, but a different design. If you drew some sort of model diagram,
you would see that you have created a triangle between the three
entities, which is (almost) always a Very Bad Idea. You would also
have to model the same color (e.g. Blue) multiple times - one for each
design; and model each size (S/M/L) once for each color/design

You have a need for an explicit join model. There are a few different
ways of modelling this, but let's introduce a new model class calle
Variation - this is a fairly common term in this kind of situation.
Normally, each Variation of a product in a shop will have it's own
unique product number of some sort.
Your model might look like this:

  belongs_to :design
  belongs_to :color
  belongs_to :size

  has_many :variations
  has_many :colors, :through=>:variations
  has_many :sizes, :through=>:variations

This way, while logically your Design model offers the same access to
the colors and sizes, you have created a *derived* relationship
between the classes, which is much preferrable to the Triangle Of

To get a list of colors for a chosen design is simple:

To get a list of all variations for a design and a color (from which
you can get the sizes):

Or get the sizes directly:
some_design.variations.find_by_color_id(the_color_id).collect { |v| v.size }

The last two should probably be implemented as methods on the Design
class (get_variations_for_color(color), get_sizes_for_color(color))

You could then ad the stock quantities to the Variaion model, or model
them in a separate table with a has_one relationship.


Awesome info Max! I'm working on modeling a scenario of my own and
although it's a little bit different from this one, reading your post
on how to tackle this problem was VERY insightful.