I’m new to rails and I’m creating an e-commerce site for a personal/learning project. Learning about associations, how would I model a scenario where Users have many Orders and Orders have many Products?
The answer seems pretty contained in your question!
class User < ApplicationRecord has_many :orders end class Order < ApplicationRecord has_many :products belongs_to :user end class Product < ApplicationRecord belongs_to :order end
However! My experience building ecommerce sites is that that exact approach will get you into trouble. You probably actually want a has-and-belongs-to-many relationship between Orders and Products. Here’s why:
A relationship where an Order has many Products implies that each Product will have only one Order. So if User A and User B both try to order Hello Kitty notebooks, too bad so sad. Whoever gets there first will purchase the only notebook available for sale, and the other person will be left out in the cold.
With a has-and-belongs-to-many relationship, we create a “join model” that belongs to both Product and Order. That way, Products can have many Orders through that join model, and vice versa. So multiple users can order their Hello Kitty notebooks and have things turn out fine.
Rails gives you two ways to model a has-and-belongs-to-many relationship. The one I’d recommend would be using a explicit join model with
has_many through:. To do this, you’d create a model to sit “in between” Order and Product.
OrderProduct would be the name a lot of devs would default to. I’ve also seen
OrderLineitem used for this exact relationship in a lot of ecommerce applications. When it’s possible to think of a domain-relevant name for your join model (like Lineitem), it’s often healthy for your application down the line when that model inevitably takes on more responsibilities.
What this would look like:
class Order < ApplicationRecord has_many :lineitems has_many :products, through: :lineitems end class Product < ApplicationRecord has_many :lineitems has_many :orders, through: :lineitems end class Lineitem < ApplicationRecord belongs_to :order belongs_to :product end
Whichever way you go, don’t forget to use the
t.references method in your migrations to add foreign key columns on models at the
belongs_to end of any association.
Hope this helps!
Thanks a lot. This is why I asked because I was learning about
has_many through: and wasn’t too sure when/where I’d use it. Your explanation clarified it.