@instance_variable не доступен внутри рубинового блока? - PullRequest
13 голосов
/ 01 марта 2011

Со следующим кодом:

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

Если вместо q используется @q, поиск всегда возвращает результаты для пустого запроса (""). Почему это? Переменная @q недоступна для блока do ... end?

Ответы [ 2 ]

20 голосов
/ 01 марта 2011

Зависит от того, как вызывается блок. Если он вызывается с использованием ключевого слова yield или метода Proc#call, вы сможете использовать переменные вашего экземпляра в блоке. Если он вызывается с помощью Object#instance_eval или Module#class_eval, контекст блока будет изменен, и вы не сможете получить доступ к переменным вашего экземпляра.

@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"

В вашем случае, похоже, Sunspot.search вызывает ваш блок в другом контексте, используя instance_eval, потому что блок нуждается в легком доступе к этому keywords методу.

7 голосов
/ 09 февраля 2012

Как говорит Джереми, Sunspot выполняет поиск DSL в новой области.

Чтобы использовать переменную экземпляра в блоке Sunspot.search, вам нужно передать ей аргумент. Примерно так должно работать (не проверено):

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

Смотрите здесь для лучшего объяснения: http://groups.google.com/group/ruby-sunspot/msg/d0444189de3e2725

...