RoR: "belongs_to_many"? Association headache
I can't seem to wrap my head around this, so I thought I'd post and see if anyone could help me out (please pardon the question if it's insultingly simple: it's complicated to me right now!)
I have these models:
order
service
customer
I think they speak for themselves: a service
is what the customer
buys when they place an order
.
Ok.
So, naturally, I setu开发者_Go百科p these relationships:
# a customer can have many orders
class Customer
has_many :orders
end
# an order belongs to a single customer and can have many services
class Order
belongs_to :customer
has_many :services
end
... but here's where I trip up:
# a service can belong to many orders
class Service
# belongs_to :order ???
end
Because my understanding of belongs_to
is that--if I put it there--a service could only belong to one order
(it would have only one value in the order_id
key field--currently not present--tying it to only one order, where it needs to be able to belong to many orders).
What am I missing here?
There are two ways to handle this. The first is a rails-managed many-to-many relationship. In this case, you use a "has_and_belongs_to_many" relationship in both the Order and Service models. Rails will automatically create a join table which manages the relationships. The relationships look like this:
class Order
has_and_belongs_to_many :services
end
class Service
has_and_belongs_to_many :orders
end
The second way is to manage the join table yourself through an intermediate model. In this case, you might have another model called "LineItem" that represents a Service in the context of an Order. The relationships look like this:
class LineItem
belongs_to :order
belongs_to :service
end
class Order
has_many :line_items
end
class Service
has_many :line_items
end
I prefer the second myself. It's probably just me, but I don't get as confused about what's going on when it's explicit. Plus if I ever want to add some attributes to the relationship itself (like perhaps a quantity in your case) I'm already prepared to do that.
class Customer
has_many :orders
end
class Service
has_many :orders
end
class Order
belongs_to :customer
belongs_to :service
end
The Order should have customer_id
and service_id
, because it is in a many-to-one relationship with both.
I think this Railscast will help you out - basically you have 2 options. You can use has_and_belongs_to_many
or has_many :through
.
You will also find that has_and_belongs_to_many
has been deprecated in favor of has_many :though => model_name
which gives the same (and more) functionality.
I think you have realized this but your order is really a composite domain model, sometimes called an aggregate in DDD speak.
Your Service is a really a listing of some product/service that someone can order. Your order aggregate records what someone ordered.
The aggregate as someone else said is made up of a header, the Order, which includes things like who ordered, the date, does it include taxes, shipping charge, etc. And the Order has_many OrderLineItem's. The OrderLineItem belongs_to Service and contains things like the quantity ordered, belongs_to the product/service, etc.
class Customer < ActiveRecord::Base has_many :orders end
class Order < ActiveRecord::Base belongs_to :customer end
class OrderLineItem < ActiveRecord::Base belongs_to :Order end
I personally use the OrderLineItem model name in deference to LineItem because in a system that needs to ship real products, as opposed to services, you might have allocations that link orders to inventory which would have line items and shipments that get the allocated product to the client, which also have line items. So the line item term can become very overloaded. This likely is not the case in your model because you're only doing services.
精彩评论