Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Don't apply options on sync callback updates.

When a default_scope exists on either side of a many-to-many relation
that applies options (like a sort), the resulting MongoDB command to
update the keys is invalid since MongoDB doesn't like $and queries
inside an update with a $query and $orderby options. It raises no error
in safe mode, but does log the following error in the db:

exception: invalid operator: $and code:10068 0ms

This fix removes any options in the criteria when updating the keys.

[ fix #2280 ]
  • Loading branch information...
commit 806af6c040f6f53fa9769670acd6837c2f0fa448 1 parent 4353285
@durran durran authored
View
3  CHANGELOG.md
@@ -7,6 +7,9 @@ For instructions on upgrading to newer versions, visit
### Resolved Issues
+* \#2280 Fix synchronization of many-to-many relations when an ordering default
+ scope exists on either side of the association.
+
* \#2278 `Criteria#update` now properly updates only the first matching document,
where `Criteria#update_all` will update all matching documents. (no flag vs multi).
View
14 lib/mongoid/criteria.rb
@@ -517,6 +517,20 @@ def where(expression)
super
end
+ # Get a version of this criteria without the options.
+ #
+ # @example Get the criteria without options.
+ # criteria.without_options
+ #
+ # @return [ Criteria ] The cloned criteria.
+ #
+ # @since 3.0.4
+ def without_options
+ crit = clone
+ crit.options.clear
+ crit
+ end
+
private
# Are documents in the query missing, and are we configured to raise an
View
4 lib/mongoid/relations/synchronization.rb
@@ -89,10 +89,10 @@ def update_inverse_keys(meta)
end
unless adds.empty?
- meta.criteria(adds, self.class).add_to_set(meta.inverse_foreign_key, id)
+ meta.criteria(adds, self.class).without_options.add_to_set(meta.inverse_foreign_key, id)
end
unless subs.empty?
- meta.criteria(subs, self.class).pull(meta.inverse_foreign_key, id)
+ meta.criteria(subs, self.class).without_options.pull(meta.inverse_foreign_key, id)
end
end
end
View
4 spec/app/models/breed.rb
@@ -0,0 +1,4 @@
+class Breed
+ include Mongoid::Document
+ has_and_belongs_to_many :dogs
+end
View
6 spec/app/models/dog.rb
@@ -0,0 +1,6 @@
+class Dog
+ include Mongoid::Document
+ field :name, type: String
+ has_and_belongs_to_many :breeds
+ default_scope asc(:name)
+end
View
19 spec/mongoid/relations/synchronization_spec.rb
@@ -431,4 +431,23 @@
tag.articles.should eq([ article ])
end
end
+
+ context "when the document has an ordering default scope" do
+
+ let!(:dog) do
+ Dog.create(name: "Fido")
+ end
+
+ let!(:breed) do
+ Breed.new(dog_ids: [ dog.id ])
+ end
+
+ before do
+ breed.save
+ end
+
+ it "adds the id to the inverse relation" do
+ dog.reload.breed_ids.should eq([ breed.id ])
+ end
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.