Search code examples
ruby-on-railsmongodbruby-on-rails-4mongoidmongoid4

Mongoid 1-N insert duplicate key error


I'm getting a weird behaviour from Mongoid 4.0.0 and Rails 4, I have a 1-N relationship and I get a duplicate key error index when I try to save the N side of the relationship. Let me show you some code:

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

And here is the test that fails:

    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

Executing this test yields the following:

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') }"

I've added a puts command after the creation of the collection to verify that indeed, its ID is the same that is being duplicated. Furthermore, removing the statement pur.collection_id = col.id results in the following error: NoMethodError: undefined method 'insert' for nil:NilClass which leads me to believe that when I try to save the Purchase object, Mongoid automatically tries to insert the other side of the 1-N relationship, although it is already persisted.

Note that changing pur.collection_id = col.id to pur.collection = col changes nothing.

I can solve this by changing Collection.create to Collection.new but this is not a viable solution, as you might imagine, I need to be able to create Purchases of already existing Collections.

Why is this happening? I've looked in the documentation and there is no mention of this behaviour, which in my opinion makes no sense (or maybe I've been looking at this screen for too long).

Any idea how to solve this?


Solution

  • So I've finally figured it out, renaming the model Collection to something else solved the problem, seems like Mongoid doesn't like that name for models, even in an isolated namespace engine.