2013-06-16 3 views
0

У меня есть модуль в Ruby, содержащий один метод и одну переменную:переменная Модуль не сохраняет свое состояние

module ApplicationHelper 
    @var1 = MyModel::CONST1.each_with_index.map { |item, i| [item, i] } 
    def method1 v1, v2, v3 = @var1[0] 
    #.... 
    # access to @var1 
    end 
end 

Поэтому я хочу @var1 быть переменной является то, что если бы это был метод, было бы оценил каждый доступ к нему в пределах method1. Это не разумно, и поэтому я хочу, чтобы его оценивали только один раз.

Однако, когда я называю это method1 (это вспомогательный метод) через ajax (диалог, основанный на ajax, который его использует), @ var1 оказывается равным нулю. Аналогично, во время первой загрузки страницы она заполняется, как я ожидаю.

Что мне делать?

ответ

2

Вашего контекст не то же самое (см):

module ApplicationHelper 
    p self # => ApplicationHelper 

    def method1 
    p self # => #<OtherClass:0x007fbe032cf6f0> an instance of an object 
    end 
end 

Рубин не работает, как Java в том смысле, что вы не в состоянии установить переменный экземпляр объекта в контексте модуля (или класс), как и вы. В вашем коде @var1 = MyModel::CONST1.each_with_index.map { |item, i| [item, i] } определяет переменную экземпляра var1 на фактическом объекте модуля ApplicationHelper, не на любом экземпляре.

В Ruby, когда вы только хотите определить переменные один раз, мы используем ||= запоминания трюк:

module ApplicationHelper 
    def method1 
    @var1 ||= MyModel::CONST1.each_with_index.map { |item, i| [item, i] } 
    end 
end 

Это трюк, который использует тот факт, что первый раз, когда вы ссылаетесь на переменной она будет nil и nil считается неуловимым в Ruby. Таким образом, выше строка ярлык для записи:

@var1 || @var1 = MyModel::CONST1.each_with_index.map { |item, i| [item, i] } 

ПРИМЕЧАНИЕ: Имейте в виду, что если @var1 может быть значения nil или false это будет повторно оценивать его каждый раз. Однако в этом случае. Поскольку вы используете Enumerable#map, вы получите [], а не nil, если товаров нет. Таким образом, использование будет таким, как ожидалось в этой ситуации.

У этого есть проблема с кромкой при первом вызове method1, потому что вы используете его для установки значения по умолчанию. Если мы вместо этого используем передачу сообщений вместо прямого доступа к переменной, мы можем достичь того, что вы ищете:

module ApplicationHelper 
    def method1(v1, v2, v3 = var1.first) 
    #.... 
    # all further access to @var1 is done by passing the message var1 
    tmp = var1.select{ ... } 
    end 

    def var1 
    @var1 ||= MyModel::CONST1.each_with_index.map { |item, i| [item, i] } 
    end 
end 
Смежные вопросы