2.0.0p247 :022 > @post.title
=> "Breakfast Burrito"
2.0.0p247 :023 > solr = Refinery::Books::Book.search { fulltext @post.title.split(' ').join(' OR ') }
NoMethodError: undefined method `title' for nil:NilClass
from (irb):23:in `block in irb_binding'
from /usr/local/rvm/gems/ruby-2.0.0-p247@bk_development/gems/sunspot-2.1.0/lib/sunspot/util.rb:208:in `instance_eval'
There's something I'm not picking up. FYI fulltext
is a method not a hash, search
takes a block, not a hash.
This works...
2.0.0p247 :026 > solr = Refinery::Books::Book.search { fulltext 'burrito' }
SOLR Request (13.9ms) ...
The block passed to .search
may be evaluated in a different context with the help of BasicObject#instance_eval
like (instance_exec
, class_eval
, class_exec
) method, so that the method fulltext
(and other DSL methods) defined for the receiver of instance_eval
(maybe Refinery::Books::Book
?) can be seen from the block. The magic here is Ruby changes the self
binding inside the block. The receiver of instance_eval
acts as the self
there.
Instance variable resolution also depends on self
. When you refer to @post
, you are actually fetching instance variable @post
of self
. Since the context of self
has been modified in the block, and the actual self
has no instance variable @post
, nil
is returned as the default value.
The fix is assign @post.title
to a local variable and use that variable in the .search
block.
title = @post.title
solr = Refinery::Books::Book.search { fulltext title.split(' ').join(' OR ') }
The block will capture the local binding at the place of its definition. In side the block, Ruby will first look up names in the local binding, and if missing, it will look up methods defined on self
.