Your Application's Environment
If you’re wondering how to access the session from your models, there’s a better way.
There a question which comes up quite often on the rails mailing list.
How can I access the session from my models
If you’re an MVC afficionado, you’ll realise that that’s a bad idea. Your controllers and views should be dependent on your models, not the other way around. There’s a nice clean solution to this, and I thought I’d outline it here. Most people want this to get the currently logged in user, or other relevant environmental information.
Do Nothing
One option is to simply access the session directly whenever you need it. This can be problematic when you want to change the session key. Also, if you want to store something smaller in the session, just the id for instance, you’re stuck.
Instance Variables
The most common approach I see people taking is to store to pull the User out of the session and simply store it in an instance variable called @user. While this works in a lot of cases, it’s only available in your controllers and views. Also, it’s extremely brave. If the filter fails to set @user, you may have some trouble tracking down the cause of your nil errors
Helper Functions
One approach is to stick a helper called user into your ApplicationController and your ApplicationHelper. Something like:
def user session[:user] end
This works really well for accessing the ‘logged in user’ from your controllers and views, but what about from your model methods? Within your models you don’t have access to the session, nor should you. The solution is to introduce the concept of currently logged in user to your models.
Models
As rails is multi-process and single threaded, you can store the currently logged in user in a class level variable, you just have to make sure to clear it out afterwards. Start by adding a cattr_accessor to your user class.
class User < ActiveRecord::Base cattr_accessor :current_user end
Now, in a before_filter, take the currently logged in user, and store it in that variable:
class ApplicationController < ApplicationController::Base
before_filter :set_user
after_filter :clear_user
private
def set_user
User.current_user= session[:user]
end
def clear_user
User.current_user= nil
end
end
Now in your models you can easily access the currently logged in user. If you’re wondering why you may want to go to all this trouble (4 lines of code) then take a look at Richard Livsey’s created_by & updated_by


Ryan Heneise July 29th, 2005 @ 05:16 PM
Thanks for posting – great tip!
onur turgay December 29th, 2005 @ 09:58 PM
you are writing user data into a class level variable. in production mode, aren’t the class level variables are shared between requests? maybe I misinterpret the class variable concept, but I had problems whenever I used @@variables for storing data.
pete March 26th, 2006 @ 09:42 AM
consider using ‘after_filter’ to set value = nil
-> easier gc -> no wrong data in subsequent request
Gazoduc April 5th, 2006 @ 02:07 PM
What about this solution ? It prevents models from messing with the session and provides them an access to the information they need…
I solved this problem by using (pseudo code)
def secure result = yield if result.kind_of? Array result.map { |r| r.set_visitor(session[:visitor_id]) } else result.set_visitor(session[:visitor_id]) end result end
With this in you can now do :
doc = secure { Document.new }
or
docs = secure { Document.find(:all) }
If you are interested in more in-depth view of my solution ( also securing find with scopes) : gaspard AT teti. DOT ch.
Kris April 5th, 2006 @ 04:17 PM
If you set a class variable does that effect the whole application or just the instance/thread/process any one user is accessing?
In other words if I set a class variable does that effect all logged in users?
Thanks, K.
lagroue April 9th, 2006 @ 11:09 AM
Koz wrote : > The key here is: > 1) Each process only handles one request at a time
I’d like to be sure of that, or that it will always stay the same. So you have any suggestion of further reading ?
JMW May 17th, 2006 @ 02:17 AM
How about simply accessing the current user attributes? I just want to output “Logged in as but session[:user] is nil even though I’m logged in.
How do I just access the attributes of the current logged user?
JMW May 17th, 2006 @ 02:22 AM
Ohh I got it now…
@session[‘user’].login
That will output the current user’s login. (provided ‘login’ is the column name in the user table)
But why wouldn’t @session[:user].login work? hmm.. I’m still foggy about when to use :user as opposed to ‘user’
JMW May 17th, 2006 @ 02:25 AM
Here’s a good tutorial on understanding symbols in ruby. http://glu.ttono.us/articles/2005/08/19/understanding-ruby-symbols