Rails can be configured to use any of the following to store session data.
Read more about these in lib/action_controller/session.
The default is using the file system(PStore), but you can also specify one of the other included stores or use your own class.
Scott Barron has prepared an excellent (if somewhat dated) comparison of session stores on his site.
Selecting which store to use is a one line affair (in one of your EnvironmentFiles):
config.action_controller.session_store = one_of_the_session_store_engines
)
Where one_of_the_session_store_engines is one of :active_record_store, :p_store, :drb_store, :mem_cache_store, or :memory_store
Each storage engine has its own particular settings and configuration issues that will require further attention.
Owing to the fact that the PStore, FileStore and MemoryStore session stores in Rails derive from Ruby’s CGI module, the CGI module Session documentation is a good source of information about how those session stores work.
To use ActiveRecord as a session storage mechanism, you will need a table in your database named sessions:
CREATE TABLE sessions (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sessid CHAR(32),
data TEXT,
PRIMARY KEY(id),
INDEX(sessid)
);
In case it helps anyone, I believe the new format for the sessions table (as of Rails 1.2.3 anyway) is something more like:
CREATE TABLE sessions (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
session_id varchar(255) default NULL,
data TEXT,
updated_at datetime default NULL,
PRIMARY KEY (id),
KEY index_sessions_on_session_id (session_id),
KEY index_sessions_on_updated_at (updated_at)
);
Note that the Agile Web Development with Rails book suggests adding an updated_at column to your session table. This, in theory, will be updated automatically when your session is accessed. However, this is not working for me (Rails 1.0) so YMMV.
You will also need to update your config/environment.rb file. The code below is already in your /config/environment.rb file. Simply uncomment the line, add the table above and your app is ready to use your database for session storage.
config.action_controller.session_store = :active_record_store
To use a table name other than sessions, for instance my_sessions, add the following to your environment configuration:
CGI::Session::ActiveRecordStore::Session.set_table_name "my_sessions"
If you are using
ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore
in your environment.config, you must specify
CGI::Session::ActiveRecordStore::Session.set_primary_key 'id'
to tell ActiveRecord to look for the “id” field and not the “session_id” field. Otherwise, you will get an application error due to a null value in the id field.
-Ira Burton?
As an added note to this, you might want to index the sessid field. In my session container performance tests there is quite a difference after a period of time between the two.
- This probably needs moving somewhere else, but a useful tip for ActiveRecordStore:
If you want to add something to the Sessions model (in my situation I wanted to add a user_id field to keep track of the user which this session belonged to so that I could monitor users who have an open session), you might spend hours pulling your hair out if you try something along the lines of
Session.find(:first, :conditions=> ["session_id = ?", @session.session_id]).updateAttribute("user_id", @session[:user].id)
A much better and easier way to do this, is to use the ‘model’ attribute. When using ActiveRecordStore as storage for sessions, a method ‘model’ is provided which gives you access to the DB implementation.
So, instead, do this:
@session.model.user_id = @session[:user].id
This will of course require creating a model ‘session.rb’ which extends ActiveRecord.
In order to improve performance, you might also want to make the sessid and data fields just as big as the values you will store in the session. For example, if you know that the length of the session id values is 32 you can use a statement like this one:
CREATE TABLE sessions {
id INTEGER PRIMARY KEY,
sessid CHAR(32),
data TEXT
}
The length of the data field must be long enough to accomodate the flash and therefore cannot be easily calculated in advance (I think).
Note (for pgsql users): Due to the way text fields are handled, defining a text field with a maximum width doesn’t provide any performance benefits in PostgreSQL. TEXT fields will do just fine, in fact they are a bit faster than CHAR fields since there is no padding overhead.
- Stefan Kaes
A good definition for a MySQL table is as follows. The AUTO_INCREMENT keeps you from getting duplicate id errors.
CREATE TABLE sessions (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sessid CHAR(32),
data TEXT,
PRIMARY KEY(id),
INDEX(sessid)
)
-Ira Burton?
You can customize the behaviour of the DB session store.
The following example is from Jeremy Kempers mailing list post: Avoiding session race condition in concurrent requests.
The ActiveRecordStore backend for CGI::Session allows you to plug in custom session classes. See session/active_record_store.rb in Action Pack. The default session class is a normal Active Record class named Session. An alternative, SqlBypass, is provided which duck-types with the AR class but uses straight SQL over the db connection You can use it as a starting point for pessimistic locking
class MyPessimisticSession < CGI::Session::ActiveRecordStore::SqlBypass
# Pick a database connection for straight SQL access.
self.connection = ActiveRecord::Base.connection
# Override the finder class method to do a SELECT ... FOR UPDATE.
def self.find_by_session_id(session_id)
@@connection.select_one "..."
end
end
# Use our custom session class.
CGI::Session::ActiveRecordStore.session_class = MyPessimisticSession
# Use the ActiveRecordStore for CGI sessions.
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update(
:database_manager => CGI::Session::ActiveRecordStore
)
Install MemCached (http://www.danga.com/memcached/)
apt-get install memcached
# gem install Ruby-MemCache
Or better with new and faster Mecache-Client
# gem install memcache-client
Change environment.rb to use MemCacheStore
config.action_controller.session_store = :mem_cache_store
To setup memcache-client we must to change enviroment.rb (ruby-memcache and memcache-client?)
require 'memcache'
memcache_options = {
:compression => false,
:debug => false,
:namespace => "app-#{RAILS_ENV}",
:readonly => false,
:urlencode => false
}
memcache_servers = [ '192.168.1.150:2222', '192.168.1.150:2223' ]
Rails::Initializer.run do |config|
....
config.action_controller.session_store = :mem_cache_store
...
config.action_controller.fragment_cache_store = :mem_cache_store, memcache_servers, memcache_options
...
end
...
cache_params = *([memcache_servers, memcache_options].flatten)
CACHE = MemCache.new *cache_params
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.merge!({ 'cache' => CACHE })
request 'memcache'
Category: Howto
Bath and Shower
Fragrance
Gift Sets
Hair Care
Makeup
Men’s Grooming
Shaving and Hair Removal
Skin Care
Tools and Accessories
Computers – Computer Add-Ons
Computers – Desktops
Computers – Handhelds & PDAs
Computers – Notebooks
Baby Diapering
Baby Feeding
For Moms
Baby Furniture
Baby Gear
Baby Gifts
Baby Health & Baby Care
Nursery Décor
Potty Training
Baby Safety
Baby Strollers
Rails can be configured to use any of the following to store session data.
Read more about these in lib/action_controller/session.
The default is using the file system(PStore), but you can also specify one of the other included stores or use your own class.
Scott Barron has prepared an excellent (if somewhat dated) comparison of session stores on his site.
Selecting which store to use is a one line affair (in one of your EnvironmentFiles):
config.action_controller.session_store = one_of_the_session_store_engines
)
Where one_of_the_session_store_engines is one of :active_record_store, :p_store, :drb_store, :mem_cache_store, or :memory_store
Each storage engine has its own particular settings and configuration issues that will require further attention.
Owing to the fact that the PStore, FileStore and MemoryStore session stores in Rails derive from Ruby’s CGI module, the CGI module Session documentation is a good source of information about how those session stores work.
To use ActiveRecord as a session storage mechanism, you will need a table in your database named sessions:
CREATE TABLE sessions (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sessid CHAR(32),
data TEXT,
PRIMARY KEY(id),
INDEX(sessid)
);
In case it helps anyone, I believe the new format for the sessions table (as of Rails 1.2.3 anyway) is something more like:
CREATE TABLE sessions (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
session_id varchar(255) default NULL,
data TEXT,
updated_at datetime default NULL,
PRIMARY KEY (id),
KEY index_sessions_on_session_id (session_id),
KEY index_sessions_on_updated_at (updated_at)
);
Note that the Agile Web Development with Rails book suggests adding an updated_at column to your session table. This, in theory, will be updated automatically when your session is accessed. However, this is not working for me (Rails 1.0) so YMMV.
You will also need to update your config/environment.rb file. The code below is already in your /config/environment.rb file. Simply uncomment the line, add the table above and your app is ready to use your database for session storage.
config.action_controller.session_store = :active_record_store
To use a table name other than sessions, for instance my_sessions, add the following to your environment configuration:
CGI::Session::ActiveRecordStore::Session.set_table_name "my_sessions"
If you are using
ActiveRecord::Base.primary_key_prefix_type = :table_name_with_underscore
in your environment.config, you must specify
CGI::Session::ActiveRecordStore::Session.set_primary_key 'id'
to tell ActiveRecord to look for the “id” field and not the “session_id” field. Otherwise, you will get an application error due to a null value in the id field.
-Ira Burton?
As an added note to this, you might want to index the sessid field. In my session container performance tests there is quite a difference after a period of time between the two.
- This probably needs moving somewhere else, but a useful tip for ActiveRecordStore:
If you want to add something to the Sessions model (in my situation I wanted to add a user_id field to keep track of the user which this session belonged to so that I could monitor users who have an open session), you might spend hours pulling your hair out if you try something along the lines of
Session.find(:first, :conditions=> ["session_id = ?", @session.session_id]).updateAttribute("user_id", @session[:user].id)
A much better and easier way to do this, is to use the ‘model’ attribute. When using ActiveRecordStore as storage for sessions, a method ‘model’ is provided which gives you access to the DB implementation.
So, instead, do this:
@session.model.user_id = @session[:user].id
This will of course require creating a model ‘session.rb’ which extends ActiveRecord.
In order to improve performance, you might also want to make the sessid and data fields just as big as the values you will store in the session. For example, if you know that the length of the session id values is 32 you can use a statement like this one:
CREATE TABLE sessions {
id INTEGER PRIMARY KEY,
sessid CHAR(32),
data TEXT
}
The length of the data field must be long enough to accomodate the flash and therefore cannot be easily calculated in advance (I think).
Note (for pgsql users): Due to the way text fields are handled, defining a text field with a maximum width doesn’t provide any performance benefits in PostgreSQL. TEXT fields will do just fine, in fact they are a bit faster than CHAR fields since there is no padding overhead.
- Stefan Kaes
A good definition for a MySQL table is as follows. The AUTO_INCREMENT keeps you from getting duplicate id errors.
CREATE TABLE sessions (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sessid CHAR(32),
data TEXT,
PRIMARY KEY(id),
INDEX(sessid)
)
-Ira Burton?
You can customize the behaviour of the DB session store.
The following example is from Jeremy Kempers mailing list post: Avoiding session race condition in concurrent requests.
The ActiveRecordStore backend for CGI::Session allows you to plug in custom session classes. See session/active_record_store.rb in Action Pack. The default session class is a normal Active Record class named Session. An alternative, SqlBypass, is provided which duck-types with the AR class but uses straight SQL over the db connection You can use it as a starting point for pessimistic locking
class MyPessimisticSession < CGI::Session::ActiveRecordStore::SqlBypass
# Pick a database connection for straight SQL access.
self.connection = ActiveRecord::Base.connection
# Override the finder class method to do a SELECT ... FOR UPDATE.
def self.find_by_session_id(session_id)
@@connection.select_one "..."
end
end
# Use our custom session class.
CGI::Session::ActiveRecordStore.session_class = MyPessimisticSession
# Use the ActiveRecordStore for CGI sessions.
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update(
:database_manager => CGI::Session::ActiveRecordStore
)
Install MemCached (http://www.danga.com/memcached/)
apt-get install memcached
# gem install Ruby-MemCache
Or better with new and faster Mecache-Client
# gem install memcache-client
Change environment.rb to use MemCacheStore
config.action_controller.session_store = :mem_cache_store
To setup memcache-client we must to change enviroment.rb (ruby-memcache and memcache-client?)
require 'memcache'
memcache_options = {
:compression => false,
:debug => false,
:namespace => "app-#{RAILS_ENV}",
:readonly => false,
:urlencode => false
}
memcache_servers = [ '192.168.1.150:2222', '192.168.1.150:2223' ]
Rails::Initializer.run do |config|
....
config.action_controller.session_store = :mem_cache_store
...
config.action_controller.fragment_cache_store = :mem_cache_store, memcache_servers, memcache_options
...
end
...
cache_params = *([memcache_servers, memcache_options].flatten)
CACHE = MemCache.new *cache_params
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.merge!({ 'cache' => CACHE })
request 'memcache'
Category: Howto
Bath and Shower
Fragrance
Gift Sets
Hair Care
Makeup
Men’s Grooming
Shaving and Hair Removal
Skin Care
Tools and Accessories
Computers – Computer Add-Ons
Computers – Desktops
Computers – Handhelds & PDAs
Computers – Notebooks
Baby Diapering
Baby Feeding
For Moms
Baby Furniture
Baby Gear
Baby Gifts
Baby Health & Baby Care
Nursery Décor
Potty Training
Baby Safety
Baby Strollers