Session cookie expiration time in Rails

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.extended(base)
    class << base
      alias_method :session_options_for_without_sliding, :session_options_for
      alias_method :session_options_for, :session_options_for_with_sliding
    end
  end

  def session_options_for_with_sliding(request, action) #:nodoc:
    opts = session_options_for_without_sliding(request, action)
    if opts[:session_expires_after] then
      opts[:session_expires] = Time.now + opts[:session_expires_after]
    end
    opts
  end
end

ActionController::Base.extend(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.

5 Responses to “Session cookie expiration time in Rails”

  1. Alex Golubev Says:

    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.

  2. squarewheel Says:

    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://www.ii.uj.edu.pl/~stradoms/squarewheel/sliding_sessions.zip (I’ve just learnt that I can’t upload zips to wordpress, so it’s on my university account now. I’ll look for a better place later).

  3. palash Says:

    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

  4. squarewheel Says:

    I don’t know why you expect after_expiration => :some_method to work. I’ve just grepped through rails source code - and found no file containing after_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.minute to 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.

  5. Alex Golubev Says:

    squarewheel many thanks, this one is working great :-)

Leave a Reply