Skip to content

Commit 86a4a13

Browse files
authored
MONGOID-5003 Delegate Model#find with block argument to Enumerable#find (#5352)
* MONGOID-5003 Delegate Model#find with block argument to Enumerable#find * Update lib/mongoid/findable.rb
1 parent 064293d commit 86a4a13

File tree

4 files changed

+80
-5
lines changed

4 files changed

+80
-5
lines changed

docs/release-notes/mongoid-8.0.txt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ Mongoid 7 behavior:
305305

306306

307307
``#pluck`` on Embedded Criteria Returns ``nil`` Values
308-
------------------------------------------------
308+
------------------------------------------------------
309309

310310
Mongoid 8 fixes a bug where calling ``#pluck`` on a Mongoid::Criteria
311311
for embedded documents discarded nil values. This behavior was
@@ -573,3 +573,30 @@ Calling ``tally`` on the age field yields the following:
573573

574574
The ``tally`` method accepts the dot notation and field aliases. It also
575575
allows for tallying localized fields.
576+
577+
578+
``find`` delegates to ``Enumerable#find`` when given a block
579+
------------------------------------------------------------
580+
581+
When given a block, without ``_id`` arguments, ``find`` delegates to
582+
``Enumerable#find``. Consider the following model:
583+
584+
.. code::
585+
586+
class Band
587+
include Mongoid::Document
588+
field :name, type: String
589+
end
590+
591+
Band.create!(name: "Depeche Mode")
592+
Band.create!(name: "The Rolling Stones")
593+
594+
Calling ``find`` with a block returns the first document for which the block
595+
returns ``true``:
596+
597+
.. code::
598+
599+
Band.find do |b|
600+
b.name == "Depeche Mode"
601+
end
602+
# => #<Band _id: 62c58e383282a4cbe82bd74b, name: "Depeche Mode">

lib/mongoid/findable.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ def exists?
119119
# strings will be transparently converted to +BSON::ObjectId+ instances
120120
# during query construction.
121121
#
122+
# If this method is given a block, it delegates to +Enumerable#find+ and
123+
# returns the first document of those found by the current Crieria object
124+
# for which the block returns a truthy value. If both a block and ids are
125+
# given, the block is ignored and the documents for the given ids are
126+
# returned. If a block and a Proc are given, the method delegates to
127+
# +Enumerable#find+ and uses the proc as the default.
128+
#
122129
# The +find+ method takes into account the default scope defined on the
123130
# model class, if any.
124131
#
@@ -129,8 +136,13 @@ def exists?
129136
#
130137
# @raise Errors::DocumentNotFound If not all documents are found and
131138
# the +raise_not_found_error+ Mongoid configuration option is truthy.
132-
def find(*args)
133-
with_default_scope.find(*args)
139+
def find(*args, &block)
140+
empty_or_proc = args.empty? || (args.length == 1 && args.first.is_a?(Proc))
141+
if block_given? && empty_or_proc
142+
with_default_scope.find(*args, &block)
143+
else
144+
with_default_scope.find(*args)
145+
end
134146
end
135147

136148
# Find the first +Document+ given the conditions.

spec/mongoid/criteria/findable_spec.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,42 @@
10061006
end
10071007
end
10081008
end
1009+
1010+
context "when passing in a block" do
1011+
1012+
let!(:band1) { Band.create!(name: '1') }
1013+
let!(:band2) { Band.create!(name: '2') }
1014+
let!(:band3) { Band.create!(name: '2') }
1015+
1016+
it "yields the documents to the block" do
1017+
doc = Band.find { |b| b.name == '2' }
1018+
expect(doc).to eq(band2)
1019+
end
1020+
end
1021+
1022+
context "when passing in ids and a block" do
1023+
1024+
let!(:band1) { Band.create!(name: '1') }
1025+
let!(:band2) { Band.create!(name: '2') }
1026+
let!(:band3) { Band.create!(name: '2') }
1027+
1028+
it "acts like findable find" do
1029+
docs = Band.find(band1.id, band2.id) { |b| b.name == '2' }
1030+
expect(docs).to eq([ band1, band2 ])
1031+
end
1032+
end
1033+
1034+
context "when passing in a Proc and a block" do
1035+
1036+
let!(:band1) { Band.create!(name: '1') }
1037+
let!(:band2) { Band.create!(name: '2') }
1038+
let!(:band3) { Band.create!(name: '2') }
1039+
1040+
it "acts like findable find" do
1041+
docs = Band.find(-> { 'default' }) { |b| b.name == '3' }
1042+
expect(docs).to eq('default')
1043+
end
1044+
end
10091045
end
10101046

10111047
describe "#for_ids" do

spec/mongoid/criteria_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -837,8 +837,8 @@
837837
end
838838
end
839839

840-
context "when given a Proc" do
841-
it "behaves as Enumerable" do
840+
context "when given a Proc without a block" do
841+
it "raises an error" do
842842
lambda do
843843
criteria.find(-> {"default"})
844844
# Proc is not serializable to a BSON type

0 commit comments

Comments
 (0)