Skip to content

Commit 8c79f57

Browse files
MONGOID-5686 Fix array operations in update_all (#5726)
1 parent 34f7a91 commit 8c79f57

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

lib/mongoid/extensions/hash.rb

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __consolidate__(klass)
4646
real_key = klass.database_field_name(key2)
4747

4848
value.delete(key2) if real_key != key2
49-
value[real_key] = (key == "$rename") ? value2.to_s : mongoize_for(key, klass, real_key, value2)
49+
value[real_key] = value_for(key, klass, real_key, value2)
5050
end
5151
consolidated[key] ||= {}
5252
consolidated[key].update(value)
@@ -166,6 +166,24 @@ def to_criteria
166166

167167
private
168168

169+
# Get the value for the provided operator, klass, key and value.
170+
#
171+
# This is necessary for special cases like $rename, $addToSet and $push.
172+
#
173+
# @param [ String ] operator The operator.
174+
# @param [ Class ] klass The model class.
175+
# @param [ String | Symbol ] key The field key.
176+
# @param [ Object ] value The original value.
177+
#
178+
# @return [ Object ] Value prepared for the provided operator.
179+
def value_for(operator, klass, key, value)
180+
case operator
181+
when "$rename" then value.to_s
182+
when "$addToSet", "$push" then value.mongoize
183+
else mongoize_for(operator, klass, operator, value)
184+
end
185+
end
186+
169187
# Mongoize for the klass, key and value.
170188
#
171189
# @api private

spec/mongoid/contextual/mongo_spec.rb

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3608,16 +3608,51 @@
36083608

36093609
context "when the attributes are in the correct type" do
36103610

3611-
before do
3612-
context.update_all("$set" => { name: "Smiths" })
3611+
context "when operation is $set" do
3612+
3613+
before do
3614+
context.update_all("$set" => { name: "Smiths" })
3615+
end
3616+
3617+
it "updates the first matching document" do
3618+
expect(depeche_mode.reload.name).to eq("Smiths")
3619+
end
3620+
3621+
it "updates the last matching document" do
3622+
expect(new_order.reload.name).to eq("Smiths")
3623+
end
36133624
end
36143625

3615-
it "updates the first matching document" do
3616-
expect(depeche_mode.reload.name).to eq("Smiths")
3626+
context "when operation is $push" do
3627+
3628+
before do
3629+
depeche_mode.update_attribute(:genres, ["electronic"])
3630+
new_order.update_attribute(:genres, ["electronic"])
3631+
context.update_all("$push" => { genres: "pop" })
3632+
end
3633+
3634+
it "updates the first matching document" do
3635+
expect(depeche_mode.reload.genres).to eq(["electronic", "pop"])
3636+
end
3637+
3638+
it "updates the last matching document" do
3639+
expect(new_order.reload.genres).to eq(["electronic", "pop"])
3640+
end
36173641
end
36183642

3619-
it "updates the last matching document" do
3620-
expect(new_order.reload.name).to eq("Smiths")
3643+
context "when operation is $addToSet" do
3644+
3645+
before do
3646+
context.update_all("$addToSet" => { genres: "electronic" })
3647+
end
3648+
3649+
it "updates the first matching document" do
3650+
expect(depeche_mode.reload.genres).to eq(["electronic"])
3651+
end
3652+
3653+
it "updates the last matching document" do
3654+
expect(new_order.reload.genres).to eq(["electronic"])
3655+
end
36213656
end
36223657
end
36233658

0 commit comments

Comments
 (0)