Any ideas on how to model this?

Hello,

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 columns: 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 combination.

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:

Variation   belongs_to :design   belongs_to :color   belongs_to :size

Design   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 Doom.

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

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

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.

Cheers, Max

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.