2012-12-05 2 views
1

Предположим, у меня есть модель Order, которая содержит много products. Я хочу иметь возможность отслеживать, какие продукты отправляются, а какие нет, поэтому я хотел бы отслеживать некоторые метаданные, которые сочетаются с каждым отношением. Если бы это было отношение has_one, то это было бы просто, просто вставьте еще несколько полей.Mongoid has_many с метаданными

Как я могу сделать это с has_many отношения между Order модели и Product модели чисто с использованием Mongoid?

ответ

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 
Смежные вопросы