13

With the following code:

def index
  @q = ""
  @q = params[:search][:q] if params[:search]
  q = @q
  @search = Sunspot.search(User) do
    keywords q
  end
  @users = @search.results
end

If @q is used instead of q, the search always returns results for an empty query (""). Why is this? Is the @q variable unavailable to the do...end block?

2
  • Did you try running with ruby -W2? Commented Mar 1, 2011 at 4:57
  • Thank you so much @jakeonrails for asking this, I was struggling with that problem for hours. Great answers too. Commented Apr 9, 2016 at 8:33

2 Answers 2

20

It depends on how the block is being called. If it is called using the yield keyword or the Proc#call method, then you'll be able to use your instance variables in the block. If it's called using Object#instance_eval or Module#class_eval then the context of the block will be changed and you won't be able to access your instance variables.

@x = "Outside the class"

class Test
  def initialize
    @x = "Inside the class"
  end

  def a(&block)
    block.call
  end

  def b(&block)
    self.instance_eval(&block)
  end
end

Test.new.a { @x } #=> "Outside the class"
Test.new.b { @x } #=> "Inside the class"

In your case, it looks like Sunspot.search is calling your block in a different context using instance_eval, because the block needs easy access to that keywords method.

Sign up to request clarification or add additional context in comments.

4 Comments

And this is why instance_eval is evil. See also How does instance_eval work and why does DHH hate it?
I am having this same problem with Sunspot. Is there a work around?
Although littering, you can wrap your instance variable inside methods and call them inside Sunspot's search block.
FYI, Sunspot supports both call and instance_eval. If you pass in a block param (like in Jack Zelig's answer), then it will use call. Check code reference here
7

As Jeremy says, Sunspot executes its search DSL in a new scope.

In order to use an instance variable in the Sunspot.search block, you'll need to pass it an argument. Something like this should work (not tested):

  @q = params[:search][:q] if params[:search]
  @search = Sunspot.search(User) do |query|
    query.keywords @q
  end
  @users = @search.results

See here for a better explanation: http://groups.google.com/group/ruby-sunspot/msg/d0444189de3e2725

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.