3

私は

class Item
  include Mongoid::Document
  field name, type: String
end

そして

class Pack
  include Mongoid::Document
end

各パックには、異なるアイテムを異なる数量で含めることができます。

もともとやりたかった

class Pack
  include Mongoid::Document

  field items, type: Array
end

最初に、私は試しました

a = Pack.new
a.items = []
a.items << {item: Item.first, quantity: 4}
a.save

そして私は得ました:

NoMethodError: undefined method `__bson_dump__' for #<Item:0x007faf1a56d670>

それから私は試しました:

a = Pack.new
a.items = []
a.items << {item_id: Item.first.id, quantity: 4}
a.save

しかし、今は次のようなことはできません

a.items[0].item.name

次にやってみたのが

class Item
  include Mongoid::Document
  field name, type: String
  belongs_to :item_quantity
end

class ItemQuantity
  include Mongoid::Document
  has_one :item
  belongs_to :pack
  field quantity, type: Integer
end

class Pack
  include Mongoid::Document
  has_many :item_quantity
end

これは機能しますが、クラッジのように感じます

これを行うにはどうすればよいですか?

4

1 に答える 1

2

あなたの最後の繰り返しは、私が過去に同様の問題を解決した方法に近いものです。私はそれをあなたの文脈に適応させようとします。私が行った主な違いは、「結合」コレクションに数量を保存しないことでした。そのため、パック内のアイテムの複数の「コピー」のそれぞれに対して、そのコレクションに新しいドキュメントが作成されます。

class Item
  include Mongoid::Document
  has_many :item_instances
end

class ItemInstance
  include Mongoid::Document
  belongs_to :item
  belongs_to :pack
end

class Pack
  include Mongoid::Document
  has_many :item_instances      
end

これにより、次のようなことができます。

pack = Pack.new
item = Item.first
pack.item_instances.build(item_id: item.id)

私はクラスがあったプリントショップ管理アプリにこれを使用しましたInvoice, Job, Product. 仕事は製品の一種の「インスタンス」であり、請求書には多くの仕事があり、それらはすべて同じ製品である可能性があるため、単純な多対多マッピングは機能しません。

また、スキーマを再考し、物事が意味のある名前になっていることを確認します. クラスの名前Item, ItemInstance, PackProduct, Item, Packそれぞれ から に変更するだけで、少しわかりやすくなります。

pack = Pack.new
product = Product.first
pack.items.build(product_id: product.id)

最後に、クラスで簡単な便利なメソッドをいくつかPack作成すると、より使いやすいインターフェイスを作成するのに大いに役立ちます。

class Pack
  def new_item(product)
    self.items.build(product_id: product.id)
  end

  def products
    self.items.map { |i| i.product }
  end
end

したがって、次のことができます。

pack.add_item(product)
# Same as using pack.items.build(product_id: product.id)

pack.products
# Returns an array (including duplicates) of all the products included in the pack.

それが役立つことを願っています。これはあまり出てこないので、他にも解決策があると思いますが、「あるオブジェクトに別のオブジェクトが複数ある」という問題を解決しようとするときに私が使用する基本的なパターンです。

クラスの使用方法に関連する独自のメソッドを追加すると、かなり使いやすくなります。また、「結合」コレクションにインデックスを設定することを忘れないでください。また、Mongoid の Github ページでこの問題を参照してください。多対多の関係に使用される配列で複数のエントリを要求しています。

それが追加された場合、必要なのは単純な関係だけである場合、将来的にはそれが進むべき道になります. 製品の印刷ジョブが作成されたときに行ったように、さらに詳細を保存する場合 (タイムスタンプ、タイトルなど)、上記のようなことを行う必要があります。

于 2012-09-23T06:47:25.757 に答える