2014-04-28 5 views
0
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/[email protected]_development/gems/sunspot-2.1.0/lib/sunspot/util.rb:208:in `instance_eval' 

내가 데리러 가지 않는 것이 있습니다. 참고 fulltext은 해시가 아니며 search은 해시가 아니라 블록을 사용합니다. .search에 전달 블록 (instance_exec, class_eval, class_exec) 방법 등 BasicObject#instance_eval의 도움으로 다른 콘텍스트에서 평가 될 수있다누군가이 블록의 Ruby 코드에 대해 설명해 주시겠습니까? 변수가 블록 내부에서 null 인 이유는 무엇입니까?

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

답변

3

이 작동 ...되도록있어서 fulltext (및 다른 DSL 방법)은 instance_eval (어쩌면 Refinery::Books::Book?)의 수신기에 대해 정의되어 있습니다. 여기에있는 마법은 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에 정의 된 메소드를 검색합니다.