mongoid/mongoid — pull request #2298 by jonhyman (2012-08-17 17:01:25+00:00)
Title: Protecting has and belongs to many relations from trying to pull against a null set of ids

I'm having an issue in one of my projects pointed at mongoid master that I can't seem to reproduce in specs on Mongoid. It's a HABTM relationship for, say, Person and House. If I do this, it fails:

```ruby
# This fails with invalid query because Person.send(:house_ids) returns nil and Mongoid this call
Person.create.destroy
# update test.houses query: { $and: [ { _id: { $in: null } } ] } update: { $pull: { person_ids: ObjectId('502e76addd365a00a4000001') } }
```

Yet this passes and works without problems:
```ruby
p = Person.create
p.house_ids
# => []
p.destroy
```

I've been trying to repro unsuccessfully in the Mongoid specs for about an hour, but this patch fixes the issue.

Also, there are a ton of unnecessary database queries happening on a #destroy. I tried to hunt those down but hit my timebox. Check out the Mongo log from a simple call to `Person.create.destroy` in the mongoid specs:

> Fri Aug 17 12:54:42 [conn86] run command mongoid_test.$cmd { count: "posts", query: { person_id: ObjectId('502e7752dd365a4ca4000001') } }
> Fri Aug 17 12:54:42 [conn86] command mongoid_test.$cmd command: { count: "posts", query: { person_id: ObjectId('502e7752dd365a4ca4000001') } } ntoreturn:1 reslen:58 0ms
> Fri Aug 17 12:54:42 [conn86] remove mongoid_test.posts query: { person_id: ObjectId('502e7752dd365a4ca4000001') } 0ms
> Fri Aug 17 12:54:42 [conn86] update mongoid_test.preferences query: { $and: [ { _id: { $in: {} } } ] } update: { $pull: { person_ids: ObjectId('502e7752dd365a4ca4000001') } } 0ms
> Fri Aug 17 12:54:42 [conn86] update mongoid_test.people query: { _id: ObjectId('502e7752dd365a4ca4000001') } update: { $set: { preference_ids: {} } } idhack:1 moved:1 0ms
> Fri Aug 17 12:54:42 [conn86] query mongoid_test.cats ntoreturn:1 scanAndOrder:1 reslen:20 0ms
Fri Aug 17 12:54:42 [conn86] query mongoid_test.homes ntoreturn:1 scanAndOrder:1 reslen:20 0ms
> Fri Aug 17 12:54:42 [conn86] update mongoid_test.events query: { $and: [ { _id: { $in: {} } } ] } update: { $pull: { administrator_ids: ObjectId('502e7752dd365a4ca4000001') } } 0ms
> Fri Aug 17 12:54:42 [conn86] update mongoid_test.people query: { _id: ObjectId('502e7752dd365a4ca4000001') } update: { $set: { administrated_event_ids: {} } } idhack:1 0ms
> Fri Aug 17 12:54:42 [conn86] remove mongoid_test.people query: { _id: ObjectId('502e7752dd365a4ca4000001') } 0ms

As you can see, there are a lot of count() operations as well as a lot of pulls that run against a blank set (_id $in nothing). In the latter cases, you should only be pulling if there is a document on which to pull. I tried to find where that change would be, but alas could not in my timebox.