有人可以解释这个Ruby代码块以及为什么变量在块内是null?

时间:2014-04-28 02:52:48

标签: ruby-on-rails ruby sunspot

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'

有些东西我没有接受。 FYI fulltext是一种方法而不是哈希,search采用块,而不是哈希。

这有效......

2.0.0p247 :026 >   solr = Refinery::Books::Book.search { fulltext 'burrito' }
  SOLR Request (13.9ms)  ...

1 个答案:

答案 0 :(得分:3)

传递给.search的块可以在BasicObject#instance_eval之类的(instance_execclass_evalclass_exec)方法的帮助下,在不同的上下文中进行评估,以便可以从块中看到为fulltext(可能是instance_eval?)的接收者定义的方法Refinery::Books::Book(以及其他DSL方法)。这里的神奇之处在于Ruby会更改块内的self绑定。 instance_eval的接收者在那里充当self

实例变量分辨率还取决于self。当您引用@post时,实际上是在获取@post的实例变量self。由于self的上下文已在块中修改,而实际的self没有实例变量@post,因此nil将作为默认值返回。

修复程序将@post.title分配给局部变量,并在.search块中使用该变量。

title = @post.title
solr = Refinery::Books::Book.search { fulltext title.split(' ').join(' OR ') }

该块将捕获其定义位置的本地绑定。在块中,Ruby将首先在本地绑定中查找名称,如果缺少,它将查找在self上定义的方法。