我有像这样定义的Mongoid类(为了简洁省略了不相关的字段):
class Product
include Mongoid::Document
belongs_to :category
end
class Order
include Mongoid::Document
embeds_many :order_items
end
class OrderItem
include Mongoid::Document
embeds_one :product
embedded_in :order
field :count, type: Integer
end
这意味着,我将产品保存在单独的收集中,当用户进行购买时,我想嵌入她在订单文档中购买的所有产品的副本(因此我有她购买的确切商品的快照以及将来编辑的内容不要改变已经购买的产品。
这是制作嵌入式副本的正确方法吗?还是应该更改我的架构?例如,创建新的文档类,如EmbeddedProduct
,并从Product
复制相关字段?
目前的解决方案似乎有效,但从我在文档和论坛中看到的内容看来,文档应该是嵌入式的,也可以是单独的集合,而不是两者。
答案 0 :(得分:0)
这个问题似乎没有得到任何关注:)
无论如何,我认为最好的方法是不将产品嵌入order_item,而是将相关字段从产品复制到order_item。
解决方案如下所示
class Product
include Mongoid::Document
# product fields like name, price, ...
belongs_to :category
end
class Order
include Mongoid::Document
# order fields like date, total_amount, address ...
embeds_many :order_items
end
class OrderItem
include Mongoid::Document
include Mongoid::MoneyField
embedded_in :order
# you can also store reference to original product
belongs_to :original_product
field :count, type: Integer
field :name
field :ean
field :sku
money_field :final_price
def self.from_product(product)
item = self.new
# ... assign fields from product, eg:
# item.name = product.name
item
end
end
当用户点击“添加到购物车”时,您可以执行以下操作:
def add
# check if product is already in the cart
order_item = @order.items.detect {|item| item.product_id == params[:product_id]}
# if not, create from product in database
if order_item.nil?
product = Product.find(params[:product_id])
order_item = OrderItem.from_product(product)
# and add to items array
@order.items.push(order_item)
end
# set count that we got from product form
# (we can do this since order_item is
# also reference to the order_item inside array of order_items)
order_item.count = params[:count]
# emit event
event = Events::CartItemChanged.new(order_item: order_item, order: @order, request_params: params)
broadcast :cart_item_changed, event
# no need to call validations since we're just adding an item
@order.save! :validate => false
redirect_to cart_path
end