problem with validates_uniqueness_of + :scope

191 views
Skip to first unread message

Ciaran

unread,
Sep 29, 2011, 12:51:29 AM9/29/11
to MongoMapper
Hi,

I'm new to mongomapper, so perhaps I'm just doing something silly, but
I can't seem to get a model to validate the uniqueness of one
attribute scoped to another.

Here's some example code that shows the problem:

class User
include MongoMapper::Document

key :email, String, :required => true
key :app_id, Integer, :required => true

validates_uniqueness_of :email, :scope => :app_id

end

u = User.new :email => 'a...@b.com', :app_id => 1
u.save

u1 = User.new :email => 'a...@b.com', :app_id => 1
u.valid? #returns true?

I also created a unique index for this constraint with:
User.ensure_index([[:app_id, 1], [:email, 1]], :unique => true)

This works, but rather than returning a RecordNotUnique type of error
message, it just fails silently after returning true when I save a
record.

If anyone else can confirm that these are bugs I'd be happy to try to
fix them.

Thanks for reading!

Jamie Orchard-Hays

unread,
Sep 29, 2011, 10:19:13 AM9/29/11
to mongo...@googlegroups.com
Versions of?

MongoDB
MongoMapper
Mongo driver

> --
> You received this message because you are subscribed to the Google
> Groups "MongoMapper" group.
> For more options, visit this group at
> http://groups.google.com/group/mongomapper?hl=en?hl=en

Ciaran

unread,
Sep 29, 2011, 1:02:39 PM9/29/11
to MongoMapper
mongo (1.3.1)
mongo_mapper (0.9.2)


On Sep 29, 7:19 am, Jamie Orchard-Hays <jamie...@gmail.com> wrote:
> Versions of?
>
> MongoDB
> MongoMapper
> Mongo driver
>
> On Sep 29, 2011, at 12:51 AM, Ciaran wrote:
>
>
>
>
>
>
>
> > Hi,
>
> > I'm new to mongomapper, so perhaps I'm just doing something silly, but
> > I can't seem to get a model to validate the uniqueness of one
> > attribute scoped to another.
>
> > Here's some example code that shows the problem:
>
> > class User
> >  include MongoMapper::Document
>
> >  key :email, String, :required => true
> >  key :app_id, Integer, :required => true
>
> >  validates_uniqueness_of :email, :scope => :app_id
>
> > end
>
> > u = User.new :email => '...@b.com', :app_id => 1
> > u.save
>
> > u1 = User.new :email => '...@b.com', :app_id => 1

Ciaran

unread,
Sep 29, 2011, 3:43:39 PM9/29/11
to MongoMapper
Sorry! Forgot to include mongo version, it's 2.0.0
C

Jamie Orchard-Hays

unread,
Sep 29, 2011, 3:57:18 PM9/29/11
to mongo...@googlegroups.com
I'm wondering if it's your MongoDB version. Users have been reporting problems with fundamental MongoMapper operations when using 2.0.0. I would try backing down to the latest 1.X.X branch of MongoDB and see if things work as expected.

Jamie

Brandon Keepers

unread,
Sep 29, 2011, 4:08:01 PM9/29/11
to mongo...@googlegroups.com
I'd second that.  I hope to look at MM and MongoDB 2 issues this week.

=b

Kevin Lawver

unread,
Sep 29, 2011, 4:22:46 PM9/29/11
to mongo...@googlegroups.com
Have you tried it with the mongo 1.4.0 (w/ bson & bson_ext, of course) gem?

On Sep 29, 2011, at 3:43 PM, Ciaran wrote:

Jamie Orchard-Hays

unread,
Sep 29, 2011, 4:50:47 PM9/29/11
to mongo...@googlegroups.com
Good call, Kevin. I was thinking that 1.3.x was latest, but it is up to 1.4.0. I'd try that before backing down MongoDB. I wouldn't be surprised if 2.0.x needs the 1.4.x Ruby Driver branch.

Dusty Doris

unread,
Sep 29, 2011, 10:02:28 PM9/29/11
to MongoMapper
It seems to work with a fresh project.

[dusty@dustybook:~/tmp/tester] $ mongod --version
db version v2.0.0, pdfile version 4.5
Thu Sep 29 22:01:41 git version:
695c67dff0ffc361b8568a13366f027caa406222

[dusty@dustybook:~/tmp/tester] $ cat Gemfile
source :rubygems
gem 'mongo_mapper'
gem 'bson_ext'

[dusty@dustybook:~/tmp/tester] $ bundle list
Gems included by the bundle:
* activemodel (3.1.0)
* activesupport (3.1.0)
* bcrypt-ruby (3.0.1)
* bson (1.4.0)
* bson_ext (1.4.0)
* builder (3.0.0)
* bundler (1.0.18)
* i18n (0.6.0)
* mongo (1.4.0)
* mongo_mapper (0.9.2)
* multi_json (1.0.3)
* plucky (0.3.8)

[dusty@dustybook:~/tmp/tester] $ cat tester.rb
require 'rubygems'
require 'bundler/setup'
require 'mongo_mapper'

MongoMapper.connection = Mongo::Connection.new
MongoMapper.database = 'tester'

class User
include MongoMapper::Document
key :email, String, :required => true
key :app_id, Integer, :required => true
validates_uniqueness_of :email, :scope => :app_id
end

[dusty@dustybook:~/tmp/tester] $ irb -r ./tester.rb
irb(main):001:0> u = User.new(:email => 'a...@b.com', :app_id => 1)
=> #<User _id: BSON::ObjectId('4e85225ce8f315a8bc000001'), app_id: 1,
email: "a...@b.com">
irb(main):002:0> u.save
=> true
irb(main):003:0> u = User.new(:email => 'a...@b.com', :app_id => 2)
=> #<User _id: BSON::ObjectId('4e85226ce8f315a8bc000003'), app_id: 2,
email: "a...@b.com">
irb(main):004:0> u.save
=> true
irb(main):005:0> u = User.new(:email => 'a...@b.com', :app_id => 1)
=> #<User _id: BSON::ObjectId('4e852278e8f315a8bc000005'), app_id: 1,
email: "a...@b.com">
irb(main):006:0> u.save
=> false
irb(main):007:0> u.errors
=> #<ActiveModel::Errors:0x007ff7ea68b408 @base=#<User _id:
BSON::ObjectId('4e852278e8f315a8bc000005'), app_id: 1, email:
"a...@b.com">, @messages={:email=>["has already been taken"]}>

Ciaran

unread,
Sep 29, 2011, 11:23:57 PM9/29/11
to MongoMapper
That's odd. I have no idea why it's not working like that for me.

Thanks so much for the replies everyone! I'll try an older version of
mongo after trying what Dusty did from scratch.
> irb(main):001:0> u = User.new(:email => '...@b.com', :app_id => 1)
> => #<User _id: BSON::ObjectId('4e85225ce8f315a8bc000001'), app_id: 1,
> email: "a...@b.com">
> irb(main):002:0> u.save
> => true
> irb(main):003:0> u = User.new(:email => '...@b.com', :app_id => 2)
> => #<User _id: BSON::ObjectId('4e85226ce8f315a8bc000003'), app_id: 2,
> email: "a...@b.com">
> irb(main):004:0> u.save
> => true
> irb(main):005:0> u = User.new(:email => '...@b.com', :app_id => 1)

Jamie Orchard-Hays

unread,
Sep 30, 2011, 10:30:11 AM9/30/11
to mongo...@googlegroups.com
I notice that Dusty is using the 1.4.x drivers. Could be the difference.

Dusty Doris

unread,
Sep 30, 2011, 11:03:27 AM9/30/11
to MongoMapper
Hmm. I just downgraded to 1.3.1 to see what would happen, still seems
to work for me. I'm just working with a Gemfile and this test file,
so I may not have everything that you are working with.

[dusty@dustybook:~/tmp/tester] $ ruby --version
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.0.1]

[dusty@dustybook:~/tmp/tester] $ cat Gemfile
source :rubygems
gem 'mongo_mapper'
gem 'mongo', '1.3.1'
gem 'bson', '1.3.1'
gem 'bson_ext', '1.3.1'

[dusty@dustybook:~/tmp/tester] $ bundle list
Gems included by the bundle:
* activemodel (3.1.0)
* activesupport (3.1.0)
* bcrypt-ruby (3.0.1)
* bson (1.3.1)
* bson_ext (1.3.1)
* builder (3.0.0)
* bundler (1.0.18)
* i18n (0.6.0)
* mongo (1.3.1)
* mongo_mapper (0.9.2)
* multi_json (1.0.3)
* plucky (0.3.8)

irb(main):003:0> u = User.new(:email => 'a...@b.com', :app_id => 1)
=> #<User _id: BSON::ObjectId('4e85d970e8f315af31000001'), app_id: 1,
email: "a...@b.com">
irb(main):004:0> u.save
=> true
irb(main):005:0> u = User.new(:email => 'a...@b.com', :app_id => 2)
=> #<User _id: BSON::ObjectId('4e85d975e8f315af31000003'), app_id: 2,
email: "a...@b.com">
irb(main):006:0> u.save
=> true
irb(main):007:0> u = User.new(:email => 'a...@b.com', :app_id => 1)
=> #<User _id: BSON::ObjectId('4e85d97ae8f315af31000005'), app_id: 1,
email: "a...@b.com">
irb(main):008:0> u.save
=> false
irb(main):009:0> u.errors
=> #<ActiveModel::Errors:0x007fa79bdde768 @base=#<User _id:
BSON::ObjectId('4e85d97ae8f315af31000005'), app_id: 1, email:
"a...@b.com">, @messages={:email=>["has already been taken"]}>


Ciaran

unread,
Sep 30, 2011, 2:13:11 PM9/30/11
to MongoMapper
Thanks so much for all the help guys. I think this must be something
to do with the specific gem bundle I'm using. I'm on rails 3.0, so the
activemodel version is not the same as what you are using. I'll try to
upgrade soon but in the meantime will just write a custom validation.
> irb(main):003:0> u = User.new(:email => '...@b.com', :app_id => 1)
> => #<User _id: BSON::ObjectId('4e85d970e8f315af31000001'), app_id: 1,
> email: "a...@b.com">
> irb(main):004:0> u.save
> => true
> irb(main):005:0> u = User.new(:email => '...@b.com', :app_id => 2)
> => #<User _id: BSON::ObjectId('4e85d975e8f315af31000003'), app_id: 2,
> email: "a...@b.com">
> irb(main):006:0> u.save
> => true
> irb(main):007:0> u = User.new(:email => '...@b.com', :app_id => 1)

Ciaran

unread,
Oct 2, 2011, 5:05:11 PM10/2/11
to MongoMapper
Interestingly, this issue resolved itself when I removed the
meta_where gem from my gem bundle.
C

Jon Kern

unread,
Nov 25, 2011, 9:39:43 PM11/25/11
to MongoMapper
I found the same issue with ensure_index([[:blah,1]], :unique => true)
not working the same as key :blah, :unique => true

The index created appears to be the same, which leads me to believe it
is something deeper inside of mongomapper.

I created a separate thread on this just now...
http://groups.google.com/group/mongomapper/t/f005e76fb5157107?hl=en%3Fhl%3Den

On Sep 28, 11:51 pm, Ciaran <ciaran....@gmail.com> wrote:
...
> I also created auniqueindex for this constraint with:
> User.ensure_index([[:app_id, 1], [:email, 1]], :unique=> true)

jnunemaker

unread,
Feb 3, 2012, 4:06:15 PM2/3/12
to mongo...@googlegroups.com
Yep, :unique is a validation, :index is to create a boring old index. This is why I know longer use :index on keys and instead put my indexes in a separate file/rake task.
Reply all
Reply to author
Forward
0 new messages