BlueFish
BlueFish

Reputation: 5135

After creating indexes using Mongoid, models fail to persist in mongodb

I've got a really bizarre problem.

Here's the stack:

I ran the rake command rake db:mongoid:create_indexes and it looks like the indexes have all been created as such:

MONGOID: Created indexes on Mongoid::GridFS::Fs::Chunk:
MONGOID: Index: {:files_id=>1, :n=>-1}, Options: {:unique=>true}
MONGOID: Created indexes on Mongoid::GridFS::Fs::File:
MONGOID: Index: {:filename=>1}, Options: {:unique=>true}
...
...
MONGOID: Created indexes on User:
MONGOID: Index: {:token=>1}, Options: {:unique=>true}
...

Then I create a user:

u = User.create!(params)
u.persisted?
 => true

If I then use the mongo shell, I can clearly see that nothing was persisted. Similarly, User.count also doesn't return the right number.

What am I missing?

Upvotes: 0

Views: 425

Answers (1)

BlueFish
BlueFish

Reputation: 5135

I discovered the problem. This is more to do with a gotcha so I thought I'd post it just in case anybody else has a similar problem. Turns out it was the way I was using Mongoid.

I had a base class as such:

class PersistentModel
  include Mongoid::Document
  ..
  # Common class and instance methods that I need across any persistent model
  ..
end

class User < PersistentModel
  # User methods
end

Turns out that this will work fine as in you will not notice any failures from the Ruby end. Everything will persist.

But if you dig in the mongodb end, you will find everything is persisted in the persistent_models collection which is not what you would expect given there are separate User models. It also creates havoc on your indexes, as all the indexes are generated against the one collection, causing collisions and problems (ie. another symptom is that the rake db:mongoid:create_indexes command will report multiple indexes created on models that don't have any index specified on those fields).

The solution is to do this...

module PersistentModel
  def self.included(base)
    base.instance_eval do
      include Mongoid::Document
      ..
      # Common class and instance methods that I need across any persistent model
      ..          
    end
  end
end

class User
  include PersistentModel
  ..
end

This way, you can still have an area to place "common" methods that you may need across any mongoid model, and Mongoid::Document is mixed in to the real model class, generating the right collections at the mongodb end.

Handy Troubleshooting Tips

These are some tips which if I had known earlier would have saved me some time...

  1. Set safe mode in your mongoid.yml configuration file to true
    • I didn't have this on, and this is why save was successful, even though there was an underlying error. The error being that the index couldn't be generated because the value was nil.
  2. Use mongo shell and look at what mongoid is persisting
  3. Check your the indexes that mongoid is generating

Upvotes: 2

Related Questions