Ruby on Rails: инициализация переменных экземпляра с помощью помощников - PullRequest
4 голосов
/ 24 января 2010

Я сталкиваюсь с некоторой проблемой области видимости, которая препятствует правильной инициализации переменных экземпляра помощниками, вызываемыми из представления.

#sample_controller.rb
class SampleController < ApplicationController
  def test
  end
end

#application_controller.rb
helper_method :display 
def display
  if not defined? @display
    return @display = "a"
  else
    return @display += "a"
  end
end

#test.html.erb
<%= display %>
<%= display %>
<%= @display %>
<%= @display.reverse %>

Когда отображается образец / тест, он умирает с ошибкой «при оценке nil.reverse». Это удивительно, потому что первые два вызова для отображения должны были инициализировать @display, я бы подумал. Если <% = @ display.reverse%> удалено, вывод будет «a aa», указывая, что переменная экземпляра @display устанавливается вспомогательным методом, но нет доступа к ней в представлении.

Если контроллер изменен таким образом, чтобы он стал (с исходным кодом вида):

class SampleController < ApplicationController
  def test
    display
  end
end

Выход становится «аа ааа а а». Если я сделаю 2 вызова для отображения в контроллере, я получу «ааа аааа аа аа». Поэтому кажется, что только вызовы, сделанные в контроллере, изменят переменную экземпляра SampleController, тогда как вызовы в представлении изменят переменную экземпляра для ApplicationController, к которому у представления нет доступа.

Это ошибка в Rails или я неправильно понимаю, и это по какой-то причине предназначенная функциональность?

Контекст, в котором я столкнулся с этой ошибкой, пытается создать logged_in? Метод ApplicationController, который устанавливает переменную @user при первом вызове и возвращает true или false, если пользователь вошел в систему. Это не будет работать, если я не добавлю ненужный вызов в контроллер, прежде чем пытаться использовать его в представлении.

Ответы [ 2 ]

6 голосов
/ 25 января 2010

Есть два @display ivars во время рендеринга, один в контроллере и один в представлении. Представление не может получить доступ к тому в контроллере и наоборот. В начале рендеринга Rails копирует все контроллеры ivar в представление. Но в то время @display не существует и не копируется. В любой ruby-программе вызов @my_undefined_ivar вернет nil - именно это и происходит с вами.

Может быть, сбивает с толку, здесь сказано по-другому. Rails копирует ivars из контроллера в представление в начале рендера. Таким образом, изменения в представлении ivar не отражаются в контроллере ivar и наоборот. Определенный вами помощник позволяет представлению вызывать метод на контроллере, поэтому ивар контроллера может быть возвращен обратно в представление в качестве возвращаемого значения, но изменение самого ива контроллера не отражается в другом представлении, иваре.

Просто используйте вспомогательный метод в этом случае и забудьте о @display в представлении.

0 голосов
/ 24 января 2010

Я думаю, это может быть вторая зарезервированная фраза проблема, которую я видел на этой неделе ...

Совет: вам почти никогда не нужно использовать ключевое слово return в Ruby. Кроме того, ваше использование defined? сводит меня с ума ... может быть стоит попробовать это:

  if @display.nil?
    @display = "a"
  else
    @display += "a"
  end
...