Skip to content

Commit 75d1b51

Browse files
MONGOID-5125 find: does not return the correct results for has_many relations (#5012)
Co-authored-by: Dmitry Rybakov <[email protected]>
1 parent 2f3505c commit 75d1b51

File tree

4 files changed

+109
-9
lines changed

4 files changed

+109
-9
lines changed

lib/mongoid/association/embedded/embeds_many/proxy.rb

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,17 +210,29 @@ def exists?
210210
# Finds a document in this association through several different
211211
# methods.
212212
#
213+
# This method delegates to +Mongoid::Criteria#find+. If this method is
214+
# not given a block, it returns one or many documents for the provided
215+
# _id values.
216+
#
217+
# If this method is given a block, it returns the first document
218+
# of those found by the current Criteria object for which the block
219+
# returns a truthy value.
220+
#
213221
# @example Find a document by its id.
214222
# person.addresses.find(BSON::ObjectId.new)
215223
#
216224
# @example Find documents for multiple ids.
217225
# person.addresses.find([ BSON::ObjectId.new, BSON::ObjectId.new ])
218226
#
227+
# @example Finds the first matching document using a block.
228+
# person.addresses.find { |addr| addr.state == 'CA' }
229+
#
219230
# @param [ Array<Object> ] args Various arguments.
231+
# @param [ Proc ] block Optional block to pass.
220232
#
221-
# @return [ Array<Document>, Document ] A single or multiple documents.
222-
def find(*args)
223-
criteria.find(*args)
233+
# @return [ Document | Array<Document> | nil ] A document or matching documents.
234+
def find(*args, &block)
235+
criteria.find(*args, &block)
224236
end
225237

226238
# Instantiate a new embeds_many association.

lib/mongoid/association/referenced/has_many/proxy.rb

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,25 +185,37 @@ def exists?
185185
criteria.exists?
186186
end
187187

188-
# Find the matchind document on the association, either based on id or
188+
# Find the matching document on the association, either based on id or
189189
# conditions.
190190
#
191+
# This method delegates to +Mongoid::Criteria#find+. If this method is
192+
# not given a block, it returns one or many documents for the provided
193+
# _id values.
194+
#
195+
# If this method is given a block, it returns the first document
196+
# of those found by the current Criteria object for which the block
197+
# returns a truthy value.
198+
#
191199
# @example Find by an id.
192200
# person.posts.find(BSON::ObjectId.new)
193201
#
194202
# @example Find by multiple ids.
195203
# person.posts.find([ BSON::ObjectId.new, BSON::ObjectId.new ])
196204
#
205+
# @example Finds the first matching document using a block.
206+
# person.addresses.find { |addr| addr.state == 'CA' }
207+
#
197208
# @note This will keep matching documents in memory for iteration
198209
# later.
199210
#
200211
# @param [ BSON::ObjectId, Array<BSON::ObjectId> ] args The ids.
212+
# @param [ Proc ] block Optional block to pass.
201213
#
202-
# @return [ Document, Criteria ] The matching document(s).
214+
# @return [ Document | Array<Document> | nil ] A document or matching documents.
203215
#
204216
# @since 2.0.0.beta.1
205-
def find(*args)
206-
matching = criteria.find(*args)
217+
def find(*args, &block)
218+
matching = criteria.find(*args, &block)
207219
Array(matching).each { |doc| _target.push(doc) }
208220
matching
209221
end

spec/mongoid/association/embedded/embeds_many/proxy_spec.rb

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,12 +1417,12 @@ class TrackingIdValidationHistory
14171417
expect(person.addresses.any?).to be true
14181418
end
14191419
end
1420-
1420+
14211421
context "when documents are not persisted" do
14221422
before do
14231423
person.addresses.build(street: "Bond")
14241424
end
1425-
1425+
14261426
it "returns true" do
14271427
expect(person.addresses.any?).to be true
14281428
end
@@ -2148,6 +2148,44 @@ class TrackingIdValidationHistory
21482148
end
21492149
end
21502150
end
2151+
2152+
context "with block" do
2153+
let!(:author) do
2154+
Person.create!(title: 'Person')
2155+
end
2156+
2157+
let!(:video_one) do
2158+
author.videos.create!(title: 'video one')
2159+
end
2160+
2161+
let!(:video_two) do
2162+
author.videos.create!(title: 'video two')
2163+
end
2164+
2165+
it "finds one" do
2166+
expect(
2167+
author.videos.find do |video|
2168+
video.title == 'video one'
2169+
end
2170+
).to eq(video_one)
2171+
end
2172+
2173+
it "returns first match of multiple" do
2174+
expect(
2175+
author.videos.find do |video|
2176+
['video one', 'video two'].include?(video.title)
2177+
end
2178+
).to be_a(Video)
2179+
end
2180+
2181+
it "returns nil when not found" do
2182+
expect(
2183+
author.videos.find do |video|
2184+
video.title == 'non exiting one'
2185+
end
2186+
).to be_nil
2187+
end
2188+
end
21512189
end
21522190

21532191
describe "#find_or_create_by" do

spec/mongoid/association/referenced/has_many/proxy_spec.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,6 +2709,44 @@
27092709
end
27102710
end
27112711
end
2712+
2713+
context "with block" do
2714+
let!(:author) do
2715+
Person.create!(title: 'Person')
2716+
end
2717+
2718+
let!(:post_one) do
2719+
author.posts.create!(title: 'post one')
2720+
end
2721+
2722+
let!(:post_two) do
2723+
author.posts.create!(title: 'post two')
2724+
end
2725+
2726+
it "finds one" do
2727+
expect(
2728+
author.posts.find do |post|
2729+
post.title == 'post one'
2730+
end
2731+
).to be_a(Post)
2732+
end
2733+
2734+
it "returns first match of multiple" do
2735+
expect(
2736+
author.posts.find do |post|
2737+
['post one', 'post two'].include?(post.title)
2738+
end
2739+
).to eq(post_one)
2740+
end
2741+
2742+
it "returns nil when not found" do
2743+
expect(
2744+
author.posts.find do |post|
2745+
post.title == 'non exiting one'
2746+
end
2747+
).to be_nil
2748+
end
2749+
end
27122750
end
27132751

27142752
describe "#find_or_create_by" do

0 commit comments

Comments
 (0)