假设我有一个Order
模型,其中包含许多products
. 我希望能够跟踪哪些产品已发货,哪些未发货,因此我想跟踪与每个关系相关的一些元数据。如果这是一个has_one
关系,那么它会很简单,只需插入更多的字段。
如何使用 Mongoid 干净地通过模型和模型has_many
之间的关系来实现这一点?Order
Product
假设我有一个Order
模型,其中包含许多products
. 我希望能够跟踪哪些产品已发货,哪些未发货,因此我想跟踪与每个关系相关的一些元数据。如果这是一个has_one
关系,那么它会很简单,只需插入更多的字段。
如何使用 Mongoid 干净地通过模型和模型has_many
之间的关系来实现这一点?Order
Product
我自己解决了这个问题,我使用另一个模型OrderProduct
作为两者之间的代理。状态的实现是使用state_machine
gem 完成的。我最终将很多对产品状态机的调用封装在 Order 模型中。这使我可以在订单实例上调用.product_state(product)
或调用类似的东西。can_cancel_product?(product)
命令
class Order
include Mongoid::Document
include Mongoid::Timestamps
field :state, type: String
embeds_many :order_products
state_machine initial: :open do
...
end
def products
order_products.map do |op|
op.product
end.freeze
end
def add_product(product)
OrderProduct.create({_product: product._id, order: self})
end
def remove_product(product)
order_products.delete find_order_product(p)
end
#wrapper for product events
OrderProduct.new.state_paths.events.each do |event|
define_method "#{event}_product" do |product|
find_order_product(product).send(event)
end
define_method "can_#{event}_product?" do |product|
find_order_product(product).send("can_#{event}?")
end
end
#wrapper for product states
OrderProduct.state_machine.states.map(&:name).each do |state|
define_method "product_#{state}?" do |product|
find_order_product(product).send("#{state}?")
end
end
#wrapper for product current state
def product_state(product)
find_order_product(product).state
end
private
def find_order_product(p)
order_products.at(order_products.index do |op|
op.product == p
end)
end
end
订购产品
class OrderProduct
include Mongoid::Document
embedded_in :order
field :_product, type: Moped::BSON::ObjectId
state_machine initial: :open do
....
end
def product
Product.find(_product)
end
def product=(product)
_product = (product._id)
end
end