Mongoid 4.0.0 と Rails 4 から奇妙な動作が発生しています。1 対 N の関係があり、関係の N 側を保存しようとすると、重複キー エラー インデックスが発生します。いくつかのコードをお見せしましょう:
module MyEngine
class Collection
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
field :price, type: Integer, default: 0
has_many :purchases, class_name: 'MyEngine::Purchase'
validates_presence_of :name
end
end
module MyEngine
class Purchase
include Mongoid::Document
include Mongoid::Timestamps
field :paid, type: Integer, default: 0
belongs_to :collection, class_name: 'MyEngine::Collection'
end
end
そして、失敗するテストは次のとおりです。
test "should save purchase" do
col = Collection.create(name:'test')
pur = Purchase.new
pur.collection_id = col.id
assert pur.save, "Could not save purchase"
end
このテストを実行すると、次の結果が得られます。
Moped::Errors::OperationFailure: The operation: #<Moped::Protocol::Command
@length=74
@request_id=7
@response_to=0
@op_code=2004
@flags=[]
@full_collection_name="dummy_test.$cmd"
@skip=0
@limit=-1
@selector={:getlasterror=>1, :w=>1}
@fields=nil>
failed with error 11000: "insertDocument :: caused by :: 11000 E11000 duplicate key error index: dummy_test.loot_collections.$_id_ dup key: { : ObjectId('54c3057350686f51a8000000') }"
コレクションの作成後にコマンドを追加してputs
、実際にその ID が複製されているものと同じであることを確認しました。さらに、ステートメントを削除するpur.collection_id = col.id
と、次のエラーが発生します。NoMethodError: undefined method 'insert' for nil:NilClass
これにより、Purchase オブジェクトを保存しようとすると、Mongoid は 1-N 関係の反対側を自動的に挿入しようとしますが、それは既に永続化されています。
pur.collection_id = col.id
に変更しても何も変わらないことに注意してくださいpur.collection = col
。
に変更することCollection.create
でこれを解決できますCollection.new
が、これは実行可能な解決策ではありません。ご想像のとおり、既存のコレクションの購入を作成できるようにする必要があります。
なぜこうなった?私はドキュメントを調べましたが、この動作については言及されていません。これは私の意見では意味がありません (または、この画面を長時間見すぎている可能性があります)。
これを解決する方法はありますか?