2012-12-05 58 views
1

比方說,我有一個Order模型,其中包含許多products。我希望能夠跟蹤哪些產品已發貨,哪些未發貨,因此我想跟蹤與每個關係一起發佈的一些元數據。如果這是一個has_one關係,那麼它會很簡單,只需插入更多的字段。Mongoid has_many元數據

我怎樣才能做到這一點與Order模型,並用乾淨的一個Mongoid模型Product之間的關係has_many

回答

0

我自己解決了這個問題,我使用另一個模型OrderProduct作爲兩者之間的代理。該州的實施是使用state_machine寶石完成的。我最終在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 

OrderProduct

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