Approach #1
Conceptually, I think it's easiest to make each variant a separate Product
. In most e-commerce applications, this makes sense - each variant would have its own SKU, and might vary on any number of different attributes: size and colour might work for t-shirts, but pants may have waist size and in-seam length, for example. So, just create a bunch of Products
with the correct attributes.
However, you want variants (e.g. multiple pant sizes in the same style) to appear on the same page together. To do that, I would make a separate class (e.g. ProductGroup
) that has_many :products
. The ProductGroup
would represent all the products appearing on the same page of your store. For many products, they might be the only Product
in the ProductGroup
, but for products with size / color options, you'll have more than one.
Then, your ProductPageController#show
method can display a specific ProductGroup
. Write some controller/view helper logic to determine which attributes are shared across the members of the ProductGroup
, and display them as usual, but for any attributes that are not shared, make a <select>
or something similar to choose those attributes.
Approach #2
If you want to make a single Product
that contains all the variants, you'll need to deal with the fact that varying attributes may be different for every product. The easiest way to do that would be to store varying attributes as a serialized hash. For example, if your database is PostgreSQL, I've had very good success using the jsonb
column type. This would allow you to do something like this (if you had a jsonb column on your Product
model called variants
:
tshirt = Product.new
tshirt.variants = { size: ["S", "M", "L", "XL"], color: ["red", "blue"] }
pants = Product.new
pants.variants = { inseam: ["30", "32", "34", "36", "38"], waist: ["30", "32", "34", "36", "38"] }
Then, if you want to find out (in your controller) what the attributes are that could vary, you can just do:
tshirt.variants.keys # ["size", "color"]
pants.variants.keys # ["inseam", "waist"]
So, at the controller/view levels, you'd just need to iterate through those keys and generate a UI (e.g. <select>
) for each key.
For more information on using PostgreSQL's jsonb
in Rails, you can check out this tutorial (especially the section entitled "How Can I Do this in Rails"). There is also MySQL's json
data type, or you can check out Rails' serialize
method.