This page introduces how to change session options, both globally (for your entire application) and per controller/per action.
This page covers:
The session options that can be set are described with the process_cgi method in the ActionPack API documentation.
Owing to the fact that nearly all of the session controls in Rails derive from Ruby’s CGI module, the CGI module Session documentation is a good source of information about how sessions work.
The two places that session options can be set are:
Don’t forget to restart the server to reload any changes you’ve made changes to your environment files.
The Rails session options can be set in config/environment.rb (or even one of the files in config/environments/*.rb if you want options per environment) as such in early versions of Rails:
# Include in environment.rb's Rails::Initializer block:
config.action_controller.session :prefix => 'eliteapp.'
In later versions of Rails (e.g. 1.1.2 to 1.1.6 inclusive) many of the config entries no longer work as they used to. In the above case we need to use different code outside the Rails::Initializer block, as shown below:
# Include in environment.rb at end:
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_key] = 'eliteapp_session_id'
This is a bit clumsy so in ActionPack 1.10.0, October 2005, a neater way (see the Changelog) to do exactly the same thing was added. The following code is directly equivalent to the second example above:
ActionController::Base.session_options[:session_key] = 'eliteapp_session_id'
The session_options method just returns ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS . Note that the value in the second and third example is not just a prefix – it is the full key name to be used. With the above code, you would see a cookie called “eliteapp_session_id” rather than the default ”_session_id” in your Web browser’s cookie list, if it provides one.
In Firefox 1.5, go to Tools -> Options, Privacy pane, Cookies tab, and click on the View Cookies button. The dialogue box that appears can be left open while you close the Options window and navigate your site, which is a good way to see new cookies appear and easily delete them for testing purposes.
It’s a good idea to change the session cookie’s key to prevent conflicts with other Ruby apps from the same server. Otherwise, they all try to use a cookie called ”_session_id” and thus only one application will work properly at a time from any particular Web browser.
LarryK, Andrew HodgkinsonIf you want to set a session option differently for one environment, you can set specific session options differently for each environment. For example, on an older version of Rails we might do this:
# in config/environments/development.rb
config.action_controller.session :domain => 'mybox'
Again, this doesn’t work in newer versions of Rails; where you used to be able to do this:
config.action_controller.session :key => 'value'
...you must now do this:
ActionController::Base.session_options[:key] = 'value'
Rails Session Management module exposes session options in controllers via a simple session call
class ApplicationController < ActionController::Base
session :disabled => true
end
The session call allows for fine grain control over session options, even permitting per-action differences. See HowtoPerActionSessionOptions for more information.
To disable session support in one controller, add session :disabled => true in that controller. To disable session support in the entire application, add it to ApplicationController.
class ApplicationController < ActionController::Base
session :disabled => true
end
To re-enable it in a inheriting controller:
class SessionController < ApplicationController
session :disabled => false
end
For more info about the session macro, see HowtoPerActionSessionOptions.
A shorthand way to disable sessions is to use session :off but unlike the above method, sessions cannot be enabled later on. Only use this form if you are sure you want to permanently disable sessions in the controller or application.
Add the following to your enviroment configuration.
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS=false
Note: This solution only works for WEBrick and is not recommended for general use.
The default file system based session store, PStore, will eventually overflow the file system (pre-Rails 1.1 anyway) if you don’t do something to prevent it.
See:
http://weblog.textdrive.com/article/196/on-rails-sessions
http://www.bigbold.com/snippets/posts/show/729
http://www.realityforge.org/articles/2006/03/01/removing-stale-rails-sessions
This is probably most useful in a shared hosting environment especially if you are paranoid about what you are storing in your sessions. On older Rails:
config.action_controller.session :tmpdir => "#{RAILS_ROOT}/sessions/"
The above example will cause all of your sessions to be stored in a directory named sessions instead of the default /tmp on Unix.
For newer Rails this isn’t necessary. The Initializer will try to store session details in #{RAILS_ROOT}/tmp/sessions/ by default. It will fall back to a system-wide temporary directory if the above location doesn’t exist, so make sure the directory is present and writable if you want sessions stored within your application. If you still want to override this and set your own location, the modern equivalent of the example above is:
ActionController::Base.session_options[:tmpdir] = "/path/to/session/folder/"
Note the trailing slash character in both examples.
You can control when the current session will expire by setting the :session_expires value with a Time object. If not set, the session will terminate when the user’s browser is closed.
Note: This sets the longevity of the session cookie – I spent a lot of time looking for ways to get a persistent session cookie in Rails, but didn’t try this solution initially as I assumed it concerned the session data on the server side.
—HenrikN
You can set the :session_expires value in an environment file as directed above.
# session should not last past Jan 1, 2007
config.action_controller.session :session_expires => Time.local(2007,"jan")
# ...or for newer Rails:
ActionController::Base.session_options[:session_expires] = Time.local(2007,"jan")
Unfortunately Rails has no way to dynamically set the expiry time of the session cookie. So it is recommended that you use the following plugin, which allows you to accomplish it: http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/
Use the plugin by adding the following to your config/environment.rb:
CGI::Session.expire_after 1.month
# or whatever value you want
Caveat:
When in development mode, the following code works:
class ApplicationController < ActionController::Base
session :session_expires => 1.hour.from_now
end
The solution above has problem of using class-variables, therefore not allowing one to set this on a per-controller basis. The plugin at http://squarewheel.wordpress.com/2007/11/03/session-cookie-expiration-time-in-rails/
does not have this limitation.
The problem with the above solutions is that they, like Rails itself, make their changes in the class context. This makes them rather inflexible. Say, for instance, that you want to make persistent sessions optional through a checkbox on the login page. This sort of thing would need to be done in the instance context. To achieve this properly would require heavy modifications to Rails but there is a simple hack you can use in the meantime.
Imagine that your login page sets session[:persistent] to either Time.now or false depending on the value of a checkbox. Why Time.now? In order for the “sliding window” concept to work, a fresh cookie must be sent with every response. Rails only sends a cookie when the session data has changed so using a value like Time.now ensures that it changes every time. What I have actually found is that some internal voodoo causes the session data to change slightly anyway but it’s best to be sure! Put something like the following in your ApplicationController.
before_filter :setup
def setup
if session[:user_id]
# Reset the "sliding window" session expiry time.
if session[:persistent]
session.instance_variable_get(:@dbman).instance_variable_get(:@cookie_options)['expires'] = 3.months.from_now
session[:persistent] = Time.now
end
# Fetch the user record.
@user = User.find_by_id(session[:user_id], :readonly => true)
end
end
Et voilà!
—James “Chewi” Le Cuirot
It would be better to combine cookie expiry with a server-side expiry check. It works by setting a session[:expiration] variable when the session is first assigned, and checking whether the current time has past the expiration time.
The following code has a problem. The user will never hit the expiry time if you keep setting it in the future. You need to add MAX_SESSION_TIME to session[:creation_time].
You both fail—creation_time is unused and unnecessary.
# The expiration time.
MAX_SESSION_TIME = 60 * 60
before_filter :prepare_session
def prepare_session
if !session[:expiry_time].nil? and session[:expiry_time] < Time.now
# Session has expired. Clear the current session.
reset_session
end
# Assign a new expiry time, whether the session has expired or not.
session[:expiry_time] = MAX_SESSION_TIME.seconds.from_now
return true
end
You might want to change the domain of your sessions if your application is accessible by more than one domain. (your-site.com or www.your-site.com, for example.) By default, Rails seems to set the domain as simply the domain that the site was requested with, which is sane, but if you are, say, storing the fact that a certain user is logged in in your session, they’ll be logged out if they somehow navigate to the alternate domain.
You can prevent this if you set your session domain to something like .your-site.com. In my production.rb, I have this line:
# Old Rails:
config.action_controller.session :session_domain => '.mysite.com'
# Newer Rails:
ActionController::Base.session_options[:session_domain] = 'mysite.com'
Note the period in front of mysite in the first example – some people find that this is required, others find it must be omitted (it probably depends upon your Rails version; try it and see what works for you).
Put this in your development.rb file if you want to have it work in development (even if you have different domains, all hail different evironments!)
In Newer Rails, try this
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update
(:session_domain => ".myhappydomain.com")
How would one go about changing the session domain only for a subset of users, say admin users that are allowed to access all domains without logging in for each domain?
-d723
category:Howto
keywords: session expires
Please put a URL spam filter, I am getting tired of erasing spam :)
This page introduces how to change session options, both globally (for your entire application) and per controller/per action.
This page covers:
The session options that can be set are described with the process_cgi method in the ActionPack API documentation.
Owing to the fact that nearly all of the session controls in Rails derive from Ruby’s CGI module, the CGI module Session documentation is a good source of information about how sessions work.
The two places that session options can be set are:
Don’t forget to restart the server to reload any changes you’ve made changes to your environment files.
The Rails session options can be set in config/environment.rb (or even one of the files in config/environments/*.rb if you want options per environment) as such in early versions of Rails:
# Include in environment.rb's Rails::Initializer block:
config.action_controller.session :prefix => 'eliteapp.'
In later versions of Rails (e.g. 1.1.2 to 1.1.6 inclusive) many of the config entries no longer work as they used to. In the above case we need to use different code outside the Rails::Initializer block, as shown below:
# Include in environment.rb at end:
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:session_key] = 'eliteapp_session_id'
This is a bit clumsy so in ActionPack 1.10.0, October 2005, a neater way (see the Changelog) to do exactly the same thing was added. The following code is directly equivalent to the second example above:
ActionController::Base.session_options[:session_key] = 'eliteapp_session_id'
The session_options method just returns ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS . Note that the value in the second and third example is not just a prefix – it is the full key name to be used. With the above code, you would see a cookie called “eliteapp_session_id” rather than the default ”_session_id” in your Web browser’s cookie list, if it provides one.
In Firefox 1.5, go to Tools -> Options, Privacy pane, Cookies tab, and click on the View Cookies button. The dialogue box that appears can be left open while you close the Options window and navigate your site, which is a good way to see new cookies appear and easily delete them for testing purposes.
It’s a good idea to change the session cookie’s key to prevent conflicts with other Ruby apps from the same server. Otherwise, they all try to use a cookie called ”_session_id” and thus only one application will work properly at a time from any particular Web browser.
LarryK, Andrew HodgkinsonIf you want to set a session option differently for one environment, you can set specific session options differently for each environment. For example, on an older version of Rails we might do this:
# in config/environments/development.rb
config.action_controller.session :domain => 'mybox'
Again, this doesn’t work in newer versions of Rails; where you used to be able to do this:
config.action_controller.session :key => 'value'
...you must now do this:
ActionController::Base.session_options[:key] = 'value'
Rails Session Management module exposes session options in controllers via a simple session call
class ApplicationController < ActionController::Base
session :disabled => true
end
The session call allows for fine grain control over session options, even permitting per-action differences. See HowtoPerActionSessionOptions for more information.
To disable session support in one controller, add session :disabled => true in that controller. To disable session support in the entire application, add it to ApplicationController.
class ApplicationController < ActionController::Base
session :disabled => true
end
To re-enable it in a inheriting controller:
class SessionController < ApplicationController
session :disabled => false
end
For more info about the session macro, see HowtoPerActionSessionOptions.
A shorthand way to disable sessions is to use session :off but unlike the above method, sessions cannot be enabled later on. Only use this form if you are sure you want to permanently disable sessions in the controller or application.
Add the following to your enviroment configuration.
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS=false
Note: This solution only works for WEBrick and is not recommended for general use.
The default file system based session store, PStore, will eventually overflow the file system (pre-Rails 1.1 anyway) if you don’t do something to prevent it.
See:
http://weblog.textdrive.com/article/196/on-rails-sessions
http://www.bigbold.com/snippets/posts/show/729
http://www.realityforge.org/articles/2006/03/01/removing-stale-rails-sessions
This is probably most useful in a shared hosting environment especially if you are paranoid about what you are storing in your sessions. On older Rails:
config.action_controller.session :tmpdir => "#{RAILS_ROOT}/sessions/"
The above example will cause all of your sessions to be stored in a directory named sessions instead of the default /tmp on Unix.
For newer Rails this isn’t necessary. The Initializer will try to store session details in #{RAILS_ROOT}/tmp/sessions/ by default. It will fall back to a system-wide temporary directory if the above location doesn’t exist, so make sure the directory is present and writable if you want sessions stored within your application. If you still want to override this and set your own location, the modern equivalent of the example above is:
ActionController::Base.session_options[:tmpdir] = "/path/to/session/folder/"
Note the trailing slash character in both examples.
You can control when the current session will expire by setting the :session_expires value with a Time object. If not set, the session will terminate when the user’s browser is closed.
Note: This sets the longevity of the session cookie – I spent a lot of time looking for ways to get a persistent session cookie in Rails, but didn’t try this solution initially as I assumed it concerned the session data on the server side.
—HenrikN
You can set the :session_expires value in an environment file as directed above.
# session should not last past Jan 1, 2007
config.action_controller.session :session_expires => Time.local(2007,"jan")
# ...or for newer Rails:
ActionController::Base.session_options[:session_expires] = Time.local(2007,"jan")
Unfortunately Rails has no way to dynamically set the expiry time of the session cookie. So it is recommended that you use the following plugin, which allows you to accomplish it: http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/
Use the plugin by adding the following to your config/environment.rb:
CGI::Session.expire_after 1.month
# or whatever value you want
Caveat:
When in development mode, the following code works:
class ApplicationController < ActionController::Base
session :session_expires => 1.hour.from_now
end
The solution above has problem of using class-variables, therefore not allowing one to set this on a per-controller basis. The plugin at http://squarewheel.wordpress.com/2007/11/03/session-cookie-expiration-time-in-rails/
does not have this limitation.
The problem with the above solutions is that they, like Rails itself, make their changes in the class context. This makes them rather inflexible. Say, for instance, that you want to make persistent sessions optional through a checkbox on the login page. This sort of thing would need to be done in the instance context. To achieve this properly would require heavy modifications to Rails but there is a simple hack you can use in the meantime.
Imagine that your login page sets session[:persistent] to either Time.now or false depending on the value of a checkbox. Why Time.now? In order for the “sliding window” concept to work, a fresh cookie must be sent with every response. Rails only sends a cookie when the session data has changed so using a value like Time.now ensures that it changes every time. What I have actually found is that some internal voodoo causes the session data to change slightly anyway but it’s best to be sure! Put something like the following in your ApplicationController.
before_filter :setup
def setup
if session[:user_id]
# Reset the "sliding window" session expiry time.
if session[:persistent]
session.instance_variable_get(:@dbman).instance_variable_get(:@cookie_options)['expires'] = 3.months.from_now
session[:persistent] = Time.now
end
# Fetch the user record.
@user = User.find_by_id(session[:user_id], :readonly => true)
end
end
Et voilà!
—James “Chewi” Le Cuirot
It would be better to combine cookie expiry with a server-side expiry check. It works by setting a session[:expiration] variable when the session is first assigned, and checking whether the current time has past the expiration time.
The following code has a problem. The user will never hit the expiry time if you keep setting it in the future. You need to add MAX_SESSION_TIME to session[:creation_time].
You both fail—creation_time is unused and unnecessary.
# The expiration time.
MAX_SESSION_TIME = 60 * 60
before_filter :prepare_session
def prepare_session
if !session[:expiry_time].nil? and session[:expiry_time] < Time.now
# Session has expired. Clear the current session.
reset_session
end
# Assign a new expiry time, whether the session has expired or not.
session[:expiry_time] = MAX_SESSION_TIME.seconds.from_now
return true
end
You might want to change the domain of your sessions if your application is accessible by more than one domain. (your-site.com or www.your-site.com, for example.) By default, Rails seems to set the domain as simply the domain that the site was requested with, which is sane, but if you are, say, storing the fact that a certain user is logged in in your session, they’ll be logged out if they somehow navigate to the alternate domain.
You can prevent this if you set your session domain to something like .your-site.com. In my production.rb, I have this line:
# Old Rails:
config.action_controller.session :session_domain => '.mysite.com'
# Newer Rails:
ActionController::Base.session_options[:session_domain] = 'mysite.com'
Note the period in front of mysite in the first example – some people find that this is required, others find it must be omitted (it probably depends upon your Rails version; try it and see what works for you).
Put this in your development.rb file if you want to have it work in development (even if you have different domains, all hail different evironments!)
In Newer Rails, try this
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update
(:session_domain => ".myhappydomain.com")
How would one go about changing the session domain only for a subset of users, say admin users that are allowed to access all domains without logging in for each domain?
-d723
category:Howto
keywords: session expires
Please put a URL spam filter, I am getting tired of erasing spam :)