С Rails 3, как вы можете установить переменную сеанса в модели

session[:cannot_reason] = "no such item"

Я хотел бы установить это в моей пользовательской модели. Прямо сейчас я получаю эту ошибку:

undefined local variable or method `session' for #<User:0x00000102eb9c38>

Идеи? Благодарность

16
AnApprentice 27 Авг 2011 в 23:27

3 ответа

Лучший ответ

Есть некоторые ненужные сведения о том, должны ли модели иметь доступ к данным сеанса. Я думаю, что это глупо, поскольку сеанс на самом деле является просто еще одной формой постоянного хранилища (хотя и на гораздо более короткие временные рамки), и в Rails кажется нормальным, чтобы ваш объект домена также мог сохранять себя.

При этом не очень чистый способ сделать это - передать хэш сеанса в качестве параметра в метод User, который будет с ним работать:

class User < ...
  def mymethod(session, count)
    session[:count] = count
  end
end

Затем в вашем контроллере вы должны сделать что-то вроде:

def update
  # ...
  user.mymethod(session, count)
end

Представив, что mymethod реализует некоторую бизнес-логику, это изменит хэш session соответствующим образом. Вам не нужно передавать хэш session обратно в контроллер, потому что Ruby передает ссылки на объекты (например, хэш) - модификации вносятся деструктивно в те объекты, на которые есть ссылки.

Небольшой совет . На мой взгляд, приведенный выше пример имеет неприятный запах. Это потому, что User - это модель ActiveRecord, которая (я предполагаю) сохраняется в базе данных, и мы добавляем поведение, которое заставляет ее также сохраняться в cookie сеанса. На мой взгляд, это нарушает SRP, и этого следует избегать.

Я бы реализовал это, выделив логику хранения сеанса в отдельный объект домена, который инкапсулирует причину его существования. Может быть, например, count - это не просто «счетчик», это общее количество товаров во временной корзине пользователя.

class TemporaryCart
  def initialize(session)
    @session = session
  end

  def add_item
    # ... other item adding logic
    @session[:temporary_cart][:num_items] += 1
  end
end

Теперь ваш контроллер будет выглядеть так:

def update
  # ...
  TemporaryCart.new(session).add_item
end

Это гораздо более показательно и открывает дверь для очевидного способа абстрагироваться от кода доступа к сеансу, если вы обнаружите, что много используете хранилище сеансов. Также обратите внимание, что я поместил данные в хэш сеанса в пространство имен (но не показал эту реализацию). Я рекомендую вам сделать это, чтобы вы не наступали на собственные пальцы при добавлении других данных.

32
andrewle 27 Авг 2011 в 22:18

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

7
Michael Fairley 27 Авг 2011 в 19:37

Объект сеанса не отображается в моделях. Либо передайте его как параметр методу в вашей модели (IMHO плохо), либо определите метод в своей модели, который возвращает то, что вы хотите, а затем сохраните его в сеансе (с вашего контроллера).

class User < ...
  def item_status
    return :no_such_item
  end
end

В вашем контроллере

session[:item_status] = current_user.item_status
5
Matt 27 Авг 2011 в 19:49