2

So, I am having some issues with user authentication in embedded documents. I have two documents, one embedded in the other. A business has many members. The models look like this:

class Member
  include Mongoid::Document

  field :username,        type: String
  field :password,           type: String
  embedded_in :business

  validates :username,  :presence => true, :uniqueness => true, :length => 5..60
end

class Business
  include Mongoid::Document

  field :name,            type: String
  embeds_many :members
end

The problem is that it isn't validating the username's uniqueness in each model. When I save a member within a business, I can save a thousand of the same name. This of course is not going to work for a good authentication system. I am using Mongoid 2, Rails 3, and Ruby 1.9

Red
  • 2,256
  • 5
  • 25
  • 38

1 Answers1

7

This is a normal behavior when using embedded documents as explained here: MongoID validation

validates_uniqueness_of

Validate that the field is unique in the database: Note that for embedded documents, this will only check that the field is unique within the context of the parent document, not the entire database.

I think you want to try to create an Index in the username field that would ensure uniqueness among all the objects of that collection. Something like this:

ensureIndex({username:1},{unique:true}); 

EDIT: If you want Mongo to throw exception if a document with the same index value exists, you must avoid Mongo to do the “fire and forget” pattern. This means that the database will not wait for a response when you perform an update/write operation on a document.

And you want to pass this parameter: safe:true. By doing so Mongo should raise an exception if for any reason the document can't be inserted.

Nobita
  • 23,519
  • 11
  • 58
  • 87
  • Thank you, I must have just missed that. So I put the index on and it worked. The only issue is that when I save something that has two of the same usernames, it say true (because it passes validation) it just doesn't save. Is there anyone to get the save function to return false? – Red Feb 20 '12 at 16:29
  • This is a really good point. I've been doing some research and I believe you can pass safe:true, and that will help. Look at my edit in the answer :) – Nobita Feb 20 '12 at 18:21