Dynamic session expiration times with Rails
One of the problems with Rails that I’ve been running into recently deal with sessions–they never seem to last long enough. For long-term data, cookies are appropriate, but for an app I’ve been working on I wanted users to be able to return to their state even after a few days.
Setting the expiration date for session cookies isn’t particular difficult in Rails: pass a Time object in your config/environment.rb and you’re off and running. That works if you want your sessions to expire in two years, say, but what happens if you want your sessions to expire in a week? Wouldn’t Time.now + 1.week work? No, because the environment code is executed just the once, and unless you’re kicking your FastCGI processes over every day or so, your app will eventually be serving up session cookies that expire last Tuesday. And that’s bad. So what’s a boy to do?
Write a plugin, that’s what.
Dynamic Session Expiration! A Plugin! For Rails!
Here we go!
Installation
Got your project under Subversion source control like a good little railer?
./script/plugin install -x http://svn.codahale.com/dynamic_session_exp/trunk
Don’t use Subversion, because source control is for weaklings?
./script/plugin install http://svn.codahale.com/dynamic_session_exp/trunk
Configuration
Now, let us away to the config/environment.rb!
CGI::Session.expire_after 1.month
This does pretty much exactly what it looks like. Session cookies are served up with an expiration date set to one month after the current time.
Conclusion
I’m a little concerned that maybe there’s some really graceful way of getting Rails to deal with session cookies a bit better, or that maybe I’m ignoring some really reasonable design spec in doing this, but hey. I need this functionality, so here it is. And it’s here for you too if you need it. I haven’t written any documentation for this because it’s so damn simple.
(FYI, this is copyright © 2006, but released under the generous and humane terms of the MIT License, copies of which can be found in various places throughout the intarweb. Bombs away!)
April 10th, 2006 at 6:49am
Great job, this is exactly what I needed too. I am just learning with a little project that I started using the “login_engine”. My goal was to have users that return to the site, refresh their cookie’s expires setting 30.days.from_now and that is exactly what appears to be happing now. I have tested this on WebBrick and Apache2/FastCGI but not in production mode yet.
Will the cookie refresh in production mode too?
April 10th, 2006 at 8:30am
If you have it configured like so:
in your
config/environment.rb, then it’ll serve up session cookies that expire in a month’s time in all of your environments.May 10th, 2006 at 11:11am
I’ve tried implementing this in a current App. It works fine on WinXp. It works fine with FireFox. It even works fine with IE.
But when i try to run on Unix, lighttpd, IE stops working.
For some reason, on unix, when IE is talking to the app, the sessions become transient. Every page request causes a new session object to load up. So the expiry becomes meaningless, since you can’t remain logged in. I’m at my wits end, as to why this happens only on this combination, when unix/firefox, works fine…
Regards.
May 10th, 2006 at 11:31am
Jeez, LeRoi, that’s a strange problem you’ve found. I can’t duplicate it, either. I’m running lighttpd 1.4.11, and even accessing it via Internet Explorer 6 works fine, sessions and all.
(Well, not totally fine–I haven’t done the requisite CSS skullduggery for IE on this project yet, so it looks like a Mondrian painting. But the sessions work fine.)
Maybe check the IE6 settings?
June 12th, 2006 at 1:24pm
[...] dynamic_session_exp [...]
July 26th, 2006 at 4:26am
This looks great, thanks Coda, it’s just what I need. Simple setup too!
Dan
August 30th, 2006 at 12:41pm
Simple. Exactly what I needed. Thank you!
September 1st, 2006 at 2:06pm
Does this plugin automatically clean up the temporary ruby_sess files that ruby on rails generates as well? I assume that this is ordinarily left up to a cron job of some sort that periodically goes through the session file directory and wipes out old session temp files.
A good solution, baked into Ruby on Rails, would be great, does one exist?
Joe G
September 1st, 2006 at 3:00pm
Joe–No, it doesn’t, there isn’t really a good solution yet. Move your sessions to the database as soon as you can and set up a cron job to clean out old sessions.
September 15th, 2006 at 1:49am
[...] My solution? I removed session expiry, such that the session doesn’t expire. This means that as long as I don’t log out or close the browser, the session remains valid. So what are the other options? Unfortunately as I found out, Rails doesn’t really allow any easy means of doing dynamic session expiry. This entry in the rubyonrails wiki provides good information on the possible alternatives. Another alternative is suggested by Coda Hale in his blog. [...]
October 3rd, 2006 at 10:02am
I found the same problem that “LeRoi Isaacs” describe. Actually, I was running Webrick on Redhat. The IE can not stay login. It’s not about IE setting because I have try different machines, which those IE works with other server.
October 23rd, 2006 at 2:52am
I’d love to use this plugin, but I get a stack level too deep error. Anyone experiencing this issue?
November 17th, 2006 at 1:39pm
[...] Quick note… using THESE INSTRUCTIONS, I made the session on gosteidisso.com stick. Now users once they login they will stay logged in even if they close their browsers. The beauty of this particular setup was that I got it working without writing a single line of code… COOL! [...]
November 30th, 2006 at 10:28pm
Thanks Coda. Worked great with one gotcha on my side, gotta put the expire_after statement at the bottom of environment.rb. Makes sense but maybe worth noting above.
February 21st, 2007 at 11:35pm
Faced the same problem like Tony, had to put the expire_after statement at the bottom of environment.rb. Anyway it worked fine after that :)
April 15th, 2007 at 3:34pm
Coda… a year into programming almost by the date of my 1st post and I am still using the extension quite often. I rewrote it a bit today for a new project. Maybe if you like it you can update the repo.
class CGI
class Session
cattr_accessor :expire_after
alias :initialize_without_dynamic_session_expiry :initialize
def initialize(request, option={})
option['session_expires'] = Time.now + self.expire_after if self.expire_after
initialize_without_dynamic_session_expiry(request, option)
end
end
end
April 18th, 2007 at 4:26am
I’m wondering what would it take to modify the plugin for expiry options on a per-user basis? in my case, I have different roles with different security requirements.
May 13th, 2007 at 4:38am
[...] http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/ [...]
May 13th, 2007 at 4:38am
[...] http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/ [...]
May 16th, 2007 at 5:07pm
[...] me功能的代码。取而代之的是我找到了两种不同的解决方案一种是set all session to be persistent 另外一种是 additional long-term state on the server [...]
July 18th, 2007 at 10:23am
I’ve seen the same issue as LeRoi Isaacs and TomY above. We are using Linux Fedora, mongrel, apache and IE 6.0/7.0 seems to lose session state, meaning every request creates a new session, thus the user is not able to login (because there is no session persistence). We have not identified what is the culprit in this scenario.
But it has something to do with setting the session_expires in Rails:
Ex.
ActionController::Base.session_options[:session_expires] = 1.year.from_now
August 13th, 2007 at 7:55am
I used the subversion command to install directly into my svn tree, but that left the external svn referenced within my svn tree. So now, when I run ’svn update’ both my tree and this tree get updated. That’s awkward but livable. But I’m not seeing any clear instructions on HOW TO DELETE this from my svn tree. ’svn delete …’ followed by ’svn ci -m ” ‘ does not work to delete this alternate svn repository within my svn repository. Help would be appreciated. Thanks.
August 13th, 2007 at 10:09am
Heitzso: Edit the svn:externals property for vendor/plugins. The Subversion project has a free book which is a great resource for learning more about how Subversion works.
August 20th, 2007 at 5:42pm
This works great for me but we want to allow the user to decide how long the session is valid. Kind of like how Yahoo mail lets you check a box during sign ‘Keep me logged in for 2 weeks’. If they don’t check that box then the session should only be good while their browser is open and then only for a much shorter duration, possibly a few hours.
Is there a way to do allow a person to set the session expiry when a user logs in?
November 3rd, 2007 at 5:45am
Your solution does not allow one to set this on per-controller basis (as it uses class variables). I use sligthly different approach (similar to the one used Ken Collins above, although I didn’t find it when researching the problem earlier):
http://squarewheel.wordpress.com/2007/11/03/session-cookie-expiration-time-in-rails/
December 26th, 2007 at 1:29am
hi
i’ve installed the plugin and modified the environment.rb file.
however when i restart the server, i’m getting this error message.
./script/../config/../vendor/rails/activesupport/lib/active_support/dependencies.rb:477:in `const_missing’: uninitialized constant CGI::Session (NameError)
is there something that i missed out?
December 28th, 2007 at 1:36pm
[...] DynamicSessionExp [...]
March 31st, 2008 at 5:35am
[...] http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/ http://www.onrails.org/articles/2006/02/18/auto-login http://livsey.org/2006/6/30/persistent-logins-in-rails [...]
April 12th, 2008 at 2:54pm
Hi was the problem with IE sessions expiring (as posted by LeRoi Isaacs and TomY) ever resolved? I am having the same problem using mongrel on ubuntu. Similarly, it works fine on other browsers, but I can’t get a valid session using IE. Interestingly, it produces 2 session files as opposed to just one using the other browsers.
Thanks if you can help, I’ve tried everything…using this plugin, setting expiry, switching to db store of sessions, etc.
April 12th, 2008 at 3:13pm
Hi again, I just tried setting the Privacy Settings from Medium to Low in Internet Options, and this resolves the issue.
Is this not a common problem with Rails applications? This could not be the most ideal fix. Could it be that by default Rails cookies are not as secure as they should be, and theres something else I’m supposed to do on the server? Surely not, I’m obviously doing something wrong, but I can’t see what. Anyone care to offer advice?
Would it have something to do with *nix and IE permissions not compatible? The session file permissions are u=rw only, so that should be ok.
May 7th, 2008 at 5:01am
[...] http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/ http://www.onrails.org/articles/2006/02/18/auto-login http://livsey.org/2006/6/30/persistent-logins-in-rails [...]