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