Mongoid built-in collection answer: find
I am sending serialized data to a class that needs to access a Mongoid document that may or may not be embedded.
In the case of an inline document, I accept a variable number of arguments that I reduce
need to get the embedded document.
The code is pretty simple:
def perform(object, *arguments)
@opts = arguments.extract_options!
@object = arguments.reduce(object){|object, args| object.public_send(*args)}
# [...]
I used public_send
because AFAIK I only need to call the public methods.
However, when I try to access an inline document, I have a very strange result when @object
is an enumerator.
After some debugging, I found that for any root document object
and inline collection items
, I have:
object.items.public_send(:find)
# => #<Enumerator: ...>
object.items.send(:find) # or __send__
# => nil
The method being called doesn't match at all when I call public_send
or send
!
- How is this possible?
- This is normal? This is mistake?
public_send
seems to be calling method find
Array
( Enumerable
) but send
(or __send__
) calling method find
for Mongoid
Edit: simple reproductive case:
require 'mongoid'
class User
include Mongoid::Document
field :name, type: String
embeds_many :groups
end
class Group
include Mongoid::Document
field :name, type: String
embedded_in :user
end
Mongoid.load_configuration({
sessions: {
default: {
database: 'send_find',
hosts: [
'localhost:27017'
]
}
}
})
user = User.create(name: 'john')
user.groups.create(name: 'g1')
user.groups.create(name: 'g2')
puts "public_send :find"
puts user.groups.public_send(:find).inspect
# => #<Enumerator: [#<Group _id: 5530dea57735334b69010000, name: "g1">, #<Group _id: 5530dea57735334b69020000, name: "g2">]:find>
puts "send :find"
puts user.groups.send(:find).inspect
# => nil
puts "__send__ :find"
puts user.groups.__send__(:find).inspect
# => nil
source to share
Ok, after a few hours of debugging I found that this is actually a bug in Mongoid.
A relation is not an array, but a proxy around the array that delegates most of the methods to the array.
Since public_send
it was also delegated, but not send
also __send__
, the behavior was not the same.
See my pull request and associated commit for more information .
source to share