I noticed (and verified in the sunspot code) the following behavior
class Foo < ActiveRecord::Base
def bar
search_str = "foo"
Boo.search do
keywords(search_str)
p self.id
p self
end
end
end
In the code above, the DSL block can access the variables defined in
the context. But the self
inside block, points to an instance of
Sunspot::DSL::Search
class (instead of an instance of Foo
class.)
When I try to access self.id
, instead of getting the id
of a Foo
object; I get the id
of a Sunspot::DSL::Search
object.
I think Sunpot is doing some binding swapping/delegation magic in Util.instance_eval_or_call
method.
I am curious why Sunspot does this and why there is no warning about this behavior in documentation.
Edit:
The Sunspot search method can be found at this link
The code below will illustrate my point. In the method foo
I have block that behaves as expected. In the method bar
, the block doesn't behave.
class Order < ActiveRecord::Base
def foo
p self.class.name # prints Order
# The `self` inside the block passed to the each method
# points to an object of type Order (as expected)
# This is the normal block behavior.
[1,2,3].each do |val|
p self.class.name # prints Order
end
end
def bar
p self.class.name # prints Order
# the `self` inside the block passed to the search method
# points to an object of type Sunspot::DSL::Search.
# This is NOT the normal block behavior.
Order.search do
keywords("hello")
p self.class.name # prints Sunspot::DSL::Search
end
end
Note2
I have located the code in Sunspot source tree that modifies the normal block behavior. My question is about the reason for rigging the binding like this.
Note3
Specifically, I found an issue while invoking the id
method in side the block. The search
method delegates the method invocation inside the block to the DSL object and if it doesn't find the method then call is re-delegated to the calling context. Search method strips all but the essential methods from the DSL object before registering delegation code. The id
method is not stripped out. This is causing the problem. For all the other methods delegation works fine.
This behavior is not documented in the Sunspot method documentation.