Update — this plugin won’t work as of Rails 2.3. See comments.
Solution for 2.3 is here: http://squarewheel.pl/posts/3
By default Rails do not support setting expiration of session cookies to ” after last visit”. The code at Rails wiki shows how to set up cookie expiration for a whole application, but it does not support setting this per-controller (or per-action) like other session options, due to the use of class variables.
This became a problem for us recently, as I needed to set different session cookie expiration times for different controllers.
Here is the solution, rewritten from scratch:
# -- put this into vendor/plugins/sliding_sessions/init.rb --
module SlidingSessions
# Allows using :session_expires_after option for session cookies
# NOTE it does not perform any checks on server-side, it just
# sets the session cookie expiration time.
# see http://wiki.rubyonrails.org/rails/pages/HowtoChangeSessionOptions
# for a recipe to perform server-side expiration checks
# (C) Paweł Stradomski , released under MIT licence
def self.included(base)
base.class_eval do
alias_method_chain :set_session_options, :sliding
end
end
def set_session_options_with_sliding(request) #:nodoc:
set_session_options_without_sliding(request)
if request.session_options && request.session_options[:session_expires_after] then
request.session_options = request.session_options.clone
request.session_options[:session_expires] = Time.now + request.session_options[:session_expires_after]
# cookie store only sends cookie if data changed. But we need to send it with every request
# to update the expiration time
request.session[:sliding_session_expiration] = request.session_options[:session_expires].to_s
end
request.session_options
end
end
ActionController::Base.send(:include, SlidingSessions)
# -- end of vendor/plugins/sliding_sessions/init.rb --
The above code (module definition + ActionController::Base.extend(SlidingSessions)) should be put into vendor/plugins/sliding_sessions/init.rb
Now you can use
session :session_expires_after => 8.hour # in any controller
in any of your controllers, even application.rb
Of course it only deals with session cookies, you still need to perform server-side checks for expired sessions and write a cron job to remove stale sessions.
December 25, 2007 at 8:33 am |
Hi,
this solution seem to bee much better than the CGI::Session plugin. Yet, I can’t figure out where should I put that code. I tried to put it application.rb but it seem that I get an endless loop => calling from session_options_for_with_sliding to session_options_for_without_sliding aliased to session_options_for which is aliased to session_options_for_with_sliding.
I would appreciate if you could help me with that.
Thanks,
Alex Golubev.
December 26, 2007 at 4:30 pm |
Updated the text a bit to show where to put the code (vendor/plugins/sliding_sessions/init.rb – you’ll need to create the ‘sliding_sessions’ directory).
It’s also available now at http://squarewheel.pl/files/sliding_sessions.zip
January 3, 2008 at 8:12 am |
I have done all the things you have said, and wrote the following code in application.rb, but the code is not doing anything
session :session_expires_after => 1.minute, :after_expiration => :some_method
Please help
January 3, 2008 at 5:02 pm |
I don’t know why you expect
after_expiration => :some_methodto work. I’ve just grepped through rails source code – and found no file containingafter_expiration.Anyway, I just created an empty rails project (with rails 1.2.6), unpacked the zip above into vendor/plugins (so I had vendor/plugins/sliding_sessions/init.rb file) and added session
:session_expires_after => 1.minuteto application.rb. Checking the cookie with firefox clearly shows it expires after 1 minute, so my patch works as advertised.I’ve also checked with rails 2.0.1 and it still works without any modification.
January 23, 2008 at 8:31 am |
squarewheel many thanks, this one is working great
June 17, 2008 at 10:48 am |
It seems like the plugin doesn’t work on PRODUCTION environment, any suggestion?
June 17, 2008 at 11:03 am |
Seems that in current version of rails session options are not run for every request, but only on opening of new session. Will investigate and prepare new patch later.
June 19, 2008 at 3:19 am |
Hi, any ideas on when the patch would be ready for rails 2.1.0. I just updated from edge to the stable release and found it stopped working.
Thanks,
Mo
June 19, 2008 at 10:54 am |
Perhaps today; if I don’t manage to find time today then until then end of week.
June 19, 2008 at 9:06 pm |
Uploaded the new version. See if it works, feel free to post comments if anything goes wrong. Once again – keep in mind it only changes cookie expiration time, it does not perform any server-side checks!
To anybody interested in why it stopped working: the new cookie store only sends updated cookie if the session data changed – so if session data was kept identical in subsequent requests, then no new cookie was issued – so the browser did not update session expiration time.
June 27, 2008 at 5:43 am |
Thanks for that. Initial testing, works like a charm. Thanks for the info on why as well. Appreciate your promptness on the fix. If your ever in Melbourne, AU i’ll buy you a beer
September 20, 2008 at 8:08 am |
Your stuff works as advertised Rails 2.1.0, production environment.
Thank you for sharing this!
February 17, 2009 at 11:45 pm |
Hi! I’ve used your module with rails 2.1 and it works really well. But today I update rails to v2.3 and it stops working.
It gives me an error when starting my application:
rails/activesupport/lib/active_support/core_ext/module/aliasing.rb:33:in `alias_method’: undefined method `set_session_options’ for class `ActionController::Base’ (NameError)
from …/rails/activesupport/lib/active_support/core_ext/module/aliasing.rb:33:in `alias_method_chain’
from …/plugins/sliding_sessions/init.rb:11:in `included’
from …/plugins/sliding_sessions/init.rb:10:in `class_eval’
… and so on …
February 18, 2009 at 12:01 am |
Quicker, I’ve looked better on the Net and I’ve found that alias_method_chain is deprecated from > 2.1 (http://apidock.com/rails/Module/alias_method_chain).
Google found some recent posts about that but my knowledge about ruby and rails is not so advanced so I don’t know how to solve the problem.
February 18, 2009 at 12:17 am |
Fortunately I haven’t been working with RoR for 7 months now, so I’m a bit out-of-date on latest changes. It seems session handling had changed a lot in 2.3, the “session“ method itself is deprecated now.
I’ll look into the matter later this week, should be a simple matter of changing the plugin to use “around_filter“ and modify the session cookie… though it might not.
February 18, 2009 at 12:53 am |
Quick update—if you can set expiration period globally, for whole application, and do not need to set it up on per-controller basis, then just modify your “config/intializers/session_store.rb” and add :expire_after key with desired period. When it comes to per-controller changes, then it becomes more complicated. It seems it’s too late to change session cookie options at that time (it shouldn’t be, as the cookie is not yet sent then, but it is). A quick glance at Rack::Session middleware shows it should allow late changes to options, but I haven’t yet figured out how rails exactly use that middleware.
February 18, 2009 at 7:14 pm |
The solution is here: http://squarewheel.pl/posts/3
February 19, 2009 at 2:18 pm |
Thank you! Great job.
September 13, 2009 at 4:59 am |
Hi,
Thanks for the work on this. It seems to work great for me, but I just realized that the statement must be in the body of a controller, not in a controller method. Would you happen to know of a way to invoke the plugin from within an action method? (I want to change the cookie expiration date depending on some factors.)
As a work-around, I can redirect to another controller that simply makes the call to the plug-in in its body.
September 13, 2009 at 12:43 pm |
This plugin is obsolete, update to rails 2.3.x.
Other than that, you can try to alter request.session_options[:expires_after] in your controller method, just make sure to clone session_options first (it’s a frozen hash). I think it might not work at that stage though.
February 12, 2010 at 8:57 pm |
Hello,
This definitely didn’t work for me in 2.1.1
Application controller body had the call, however, it didn’t seem to do anything (and I added the module).
Ended up just using JS to extend the exp time.
m