Как сохранить переменную экземпляра для нескольких действий в контроллере?

Скажем, я хочу сохранить некоторую переменную в моем контроллере. Я хочу инициализировать его в одном действии, увеличивать его в другом и читать в другом. Просто объявление этой переменной с помощью @foo не работает, потому что @foo умирает после того, как действие, которое было создано, отображается.
Я не хочу, чтобы эта переменная хранилась в модели.

Есть ли способ сохранить эту переменную, кроме сохранения ее в сеансе?
Кажется, я несколько раз сталкивался с этой простой проблемой, и я хочу знать, как лучше решить ее.

Ответ 1

Не совсем. Каждый вызов действия контроллера не имеет состояния. После завершения действия контроллера ничего не доступно. Новый экземпляр контроллера создается для каждого запроса и затем отбрасывается в конце запроса.

Если вы не хотите хранить его в сеансе или в модели базы данных, у вас не так много параметров, если вы хотите, чтобы эта переменная была специфичной для определенного сеанса.

Если он является глобальным во всех сеансах, вы можете поместить его в @@class_variable, а не в @instance_variable, но это может стать беспорядочным, как только вы начнете с нескольких процессов Rails (каждый из которых будет иметь свою собственную копию), или если вы работаете в потоковом режиме, вы можете столкнуться с неприятными ошибками concurrency.

Я предполагаю, что вы могли бы посмотреть на что-то вроде memcached, но вам все равно нужно указать его на какой-то user_id или другой маркер сеанса (если он не глобальный)

Ответ 2

Мне тоже интересно, почему вы против использования сеанса? Если вам не нравится работать с сеансом непосредственно в ваших действиях, вы можете эмулировать выживающую переменную экземпляра @foo с фильтрами. Что-то вроде этого может быть?

class FooController < ApplicationController
  before_filter :load_foo
  after_filter :save_foo

  private
    def load_foo
      @foo = session[:foo] || 0
    end

    def save_foo
      session[:foo] = @foo
    end

end

Ваши действия будут иметь возможность управлять значением через переменную экземпляра @count, и это будет автоматически сохраняться в сеансе.

Ответ 3

Вы можете использовать встроенный механизм Rails.cache для хранения значения, но, как упоминалось в первом ответе, вам нужно было бы отключить что-то вроде user_id. Это хороший способ, так как вы можете поддерживать его с помощью разных механизмов хранения.

Rails.cache.write(:foo)
# in later action
Rails.cache.read(:foo)

Еще одна вещь, на которую вы могли бы обратить внимание, - это хэш флэш-памяти, который предоставляет метод keep, чтобы значение flash было больше, чем один последующий запрос.

Итак, в действии 1 вы можете создать значение:

flash[:foo] = some_value
flash.keep(:foo)

В действии 2 вы можете получить к нему доступ и снова вызвать вызов, если хотите, чтобы он оставался в живых для последующих действий.

flash[:foo] #use it for something
flash.keep(:foo) # keep it for another request

Это немного сложно сделать в контексте http-запросов.

Ответ 4

Если это простой счетчик или строка, я считаю, что лучшим решением является сохранение его в сеансе. Таким образом, он будет доступен, если вы используете несколько веб-серверов.

Почему вы против использования сеанса для этого?

Ответ 5

Не волнуйтесь, сеансы не будут кусаться.

Кроме того, сеанс, вероятно, лучший способ сделать это.