Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting a Session Variable in a Model

With Rails 3, How can you set a session variable in a model

session[:cannot_reason] = "no such item"

I'd like to set the above in my user model. Right now I get this error:

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

Ideas? Thanks

like image 334
AnApprentice Avatar asked Aug 27 '11 19:08

AnApprentice


People also ask

How do you create a session variable?

Before you can store any information in session variables, you must first start up the session. To begin a new session, simply call the PHP session_start() function. It will create a new session and generate a unique session ID for the user. The PHP code in the example below simply starts a new session.

How do you define a session variable?

A session variable is a special type of variable whose value is maintained across subsequent web pages. With session variables, user-specific data can be preserved from page to page delivering customized content as the user interacts with the web application.

How do you use session variables?

Session variables solve this problem by storing user information to be used across multiple pages (e.g. username, favorite color, etc). By default, session variables last until the user closes the browser. So; Session variables hold information about one single user, and are available to all pages in one application.

Can a user set a session variable?

The $_SESSION is stored entirely on the server, so the user cannot modify it. However, it is possible for session-hijacking exploits where the user gets connected to another user's session.


1 Answers

There's some unnecessary cargo-culting regarding whether or not models should have access to session data. I think this is silly, since session is really just another form of persistant storage (albeit for a much shorter time frame) and, in Rails, it seems ok to have your domain object also be able to persist itself.

That being said, the not very clean way to do it would be to pass the session hash as a parameter into the User method that will operate on it:

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

In your controller, you would then do something like:

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

Imagining that mymethod is implementing some business logic, this will modify the session hash appropriately. You don't have to pass the session hash back out to the controller because Ruby passes around references to objects (like a Hash)--modifications are made destructively to those referenced objects.

A word of advice: The above example, in my opinion, is smelly. This is because User is an ActiveRecord model which (I'm assuming) persists to a database and we're adding behavior that makes it also persist to a session cookie. To me, this violates SRP and should be avoided.

The way I would implement this would be to extract the session storage logic out to a separate domain object that encapsulates the reason for its existence. Maybe, for example, count isn't just a "count", it's the total of the number of items in the user's temporary cart.

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

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

Now your controller would look like this:

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

This is much more revealing and opens the door for an obvious way to abstract out session access code if you find yourself using session storage a lot. Also notice that I namespaced the data in the session hash (but didn't show this implementation). I recommend you do this so you don't step on your own toes when adding other data.

like image 61
andrewle Avatar answered Nov 15 '22 15:11

andrewle