Drop the sql_session_store plugin

The sql_session_store plugin doesn't work with rails 3 and doesn't
seem to be supported anymore, so drop it in favour of the builtin
database backed session storage.
This commit is contained in:
Tom Hughes 2011-09-30 01:02:09 +01:00
parent 1132dd36e3
commit 93fded9641
17 changed files with 6 additions and 977 deletions

View file

@ -1,8 +1,8 @@
# Be sure to restart your server when you modify this file.
OpenStreetMap::Application.config.session_store :cookie_store, :key => '_osm_session'
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rails generate session_migration")
# OpenStreetMap::Application.config.session_store :active_record_store
if STATUS == :database_offline or STATUS == :database_readonly
OpenStreetMap::Application.config.session_store :cookie_store, :key => '_osm_session'
else
ActiveRecord::SessionStore.session_class = ActiveRecord::SessionStore::SqlBypass
OpenStreetMap::Application.config.session_store :active_record_store, :key => '_osm_session'
end

View file

@ -1,8 +0,0 @@
# Work out which session store adapter to use
adapter = Rails.configuration.database_configuration[Rails.env]["adapter"]
session_class = adapter + "_session"
# Configure SqlSessionStore
unless STATUS == :database_offline
SqlSessionStore.session_class = session_class.camelize.constantize
end

View file

@ -1,20 +0,0 @@
Copyright (c) 2006 Dr.-Ing. Stefan Kaes
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,102 +0,0 @@
== SqlSessionStore
This version of SqlSessionStore properly supports both CGI-based sessions (Rails < 2.3)
and Rack-based sessions released in Rails 2.3. For the latest version of +SqlSessionStore+,
see:
http://github.com/nateware/sql_session_store/tree/master
To install, use:
script/plugin install git://github.com/nateware/sql_session_store.git
This version also includes the "native columns" feature, which enables +session[:xyz]+
to map directly to column +xyz+ in the sessions table transparently. For info,
scroll down to "Step 4".
Note: Only Mysql, PostgreSQL, and Oracle are currently supported (others work,
but you won't see much performance improvement).
== Step 1
If you have generated your sessions table using rake db:sessions:create, go to Step 2
If you're using an old version of sql_session_store, run
script/generate sql_session_store [DB]
where DB is mysql, postgresql or oracle
Then run
rake db:migrate
to create the sessions table.
== Step 2
Add the code below in +config/environment.rb+, inside the initializers section
# Use SqlSessionStore instead of the standard ActiveRecord store
config.action_controller.session_store = :sql_session_store
Then, depending on your database type, add
SqlSessionStore.session_class = MysqlSession
or
SqlSessionStore.session_class = PostgresqlSession
or
SqlSessionStore.session_class = OracleSession
after the initializer section in environment.rb
== Step 3 (optional)
If you want to use a database separate from your default one to store
your sessions, specify a configuration in your database.yml file (say
sessions), and establish the connection on SqlSession in
environment.rb:
SqlSession.establish_connection :sessions
== Step 4 (optional)
If you want to store certain pieces of data as actual columns in the
+sessions+ table transparently, simply update the sessions migration
to include the columns. For example, if you wanted to store +user_id+
and +language+ as columns, your migration might look something like:
create_table :sessions do |t|
t.string :session_id, :null => false, :references => nil, :unique => true
t.integer :user_id
t.string :language
t.text :data
t.timestamps
end
Then, use the "native columns" feature of the specific database driver:
OracleSession.native_columns = [:user_id, :language]
This will map these columns transparently for you. Simply access them like
normal columns:
session[:user_id] = @user.id
session[:language] = @language
And the appropriate columns in the sessions table will be updated for you.
== IMPORTANT NOTES
1. The class name SQLSessionStore has changed to SqlSessionStore to
let Rails work its autoload magic.
2. You will need the binary drivers for Mysql or Postgresql.
These have been verified to work:
* ruby-postgres (0.7.1.2005.12.21) with postgreql 8.1
* ruby-mysql 2.7.1 with Mysql 4.1
* ruby-mysql 2.7.2 with Mysql 5.0

View file

@ -1,22 +0,0 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
desc 'Default: run unit tests.'
task :default => :test
desc 'Test the sql_session_store plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate documentation for the sql_session_store plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'SqlSessionStore'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end

View file

@ -1,17 +0,0 @@
Description:
The sql_session_store generator creates a migration for use with
the sql session store. It takes one argument: the database
type. Only mysql and postgreql are currently supported.
Example:
./script/generate sql_session_store mysql
This will create the following migration:
db/migrate/XXX_add_sql_session.rb
Use
./script/generate sql_session_store postgreql
to get a migration for postgres.

View file

@ -1,25 +0,0 @@
class SqlSessionStoreGenerator < Rails::Generator::NamedBase
def initialize(runtime_args, runtime_options = {})
runtime_args.insert(0, 'add_sql_session')
if runtime_args.include?('postgresql')
@_database = 'postgresql'
elsif runtime_args.include?('mysql')
@_database = 'mysql'
elsif runtime_args.include?('oracle')
@_database = 'oracle'
else
puts "error: database type not given.\nvalid arguments are: mysql or postgresql"
exit
end
super
end
def manifest
record do |m|
m.migration_template("migration.rb", 'db/migrate',
:assigns => { :migration_name => "SqlSessionStoreSetup", :database => @_database },
:migration_file_name => "sql_session_store_setup"
)
end
end
end

View file

@ -1,38 +0,0 @@
class <%= migration_name %> < ActiveRecord::Migration
class Session < ActiveRecord::Base; end
def self.up
c = ActiveRecord::Base.connection
if c.tables.include?('sessions')
if (columns = Session.column_names).include?('sessid')
rename_column :sessions, :sessid, :session_id
else
add_column :sessions, :session_id, :string unless columns.include?('session_id')
add_column :sessions, :data, :text unless columns.include?('data')
if columns.include?('created_on')
rename_column :sessions, :created_on, :created_at
else
add_column :sessions, :created_at, :timestamp unless columns.include?('created_at')
end
if columns.include?('updated_on')
rename_column :sessions, :updated_on, :updated_at
else
add_column :sessions, :updated_at, :timestamp unless columns.include?('updated_at')
end
end
else
create_table :sessions, :options => '<%= database == "mysql" ? "ENGINE=MyISAM" : "" %>' do |t|
t.column :session_id, :string
t.column :data, :text
t.column :created_at, :timestamp
t.column :updated_at, :timestamp
end
add_index :sessions, :session_id, :name => 'session_id_idx'
end
end
def self.down
raise IrreversibleMigration
end
end

View file

@ -1,2 +0,0 @@
# Install hook code here
puts IO.read(File.join(File.dirname(__FILE__), 'README'))

View file

@ -1,88 +0,0 @@
#
# This is a common base class for database-specific session store implementations
#
require 'cgi/session'
require 'base64'
class AbstractSession
# if you need Rails components, and you have a pages which create
# new sessions, and embed components insides this pages that need
# session access, then you *must* set +eager_session_creation+ to
# true (as of Rails 1.0).
cattr_accessor :eager_session_creation
@@eager_session_creation = false
# Some attributes you may want to store natively in the database
# in actual columns. This allows other models and database queries
# to get to the data without having to unmarshal the data blob.
# One common example is the user_id of the session, so it can be
# related to the users table
cattr_accessor :native_columns
@@native_columns = []
# Allow the user to change the table name
cattr_accessor :table_name
@@table_name = 'sessions'
cattr_reader :timestamp_columns
@@timestamp_columns = [:created_at, :updated_at]
attr_accessor :id, :session_id, :data
def initialize(session_id, data, id=nil)
@session_id = session_id
@data = data
@id = id
end
class << self
# delete all sessions meeting a given +condition+. it is the
# caller's responsibility to pass a valid sql condition
def delete_all(condition=nil)
if condition
session_connection.exec("DELETE FROM sessions WHERE #{condition}")
else
session_connection.exec("DELETE FROM sessions")
end
end
# retrieve the session table connection and get the 'raw' driver connection from it
def session_connection
SqlSession.connection.raw_connection
end
def unmarshalize(data)
Marshal.load(Base64.decode64(data))
end
def marshalize(data)
Base64.encode64(Marshal.dump(data))
end
end
end
__END__
# This software is released under the MIT license
#
# Copyright (c) 2005, 2006, 2008 Stefan Kaes
# Copyright (c) 2008, 2009 Nate Wiger
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,103 +0,0 @@
require 'mysql'
# MysqlSession is a down to the bare metal session store
# implementation to be used with +SQLSessionStore+. It is much faster
# than the default ActiveRecord implementation.
#
# The implementation assumes that the table column names are 'id',
# 'data', 'created_at' and 'updated_at'. If you want use other names,
# you will need to change the SQL statments in the code.
class MysqlSession < AbstractSession
class << self
# try to find a session with a given +session_id+. returns nil if
# no such session exists. note that we don't retrieve
# +created_at+ and +updated_at+ as they are not accessed anywhyere
# outside this class
def find_session(session_id)
connection = session_connection
connection.query_with_result = true
result = connection.query("SELECT id, data FROM sessions WHERE `session_id`='#{session_id}' LIMIT 1")
my_session = nil
# each is used below, as other methods barf on my 64bit linux machine
# I suspect this to be a bug in mysql-ruby
result.each do |row|
my_session = new(session_id, AbstractSession.unmarshalize(row[1]))
my_session.id = row[0]
end
result.free
my_session
end
# create a new session with given +session_id+ and +data+
# and save it immediately to the database
def create_session(session_id, data={})
new_session = new(session_id, data)
if @@eager_session_creation
connection = session_connection
connection.query("INSERT INTO sessions (`created_at`, `updated_at`, `session_id`, `data`) VALUES (NOW(), NOW(), '#{session_id}', '#{Mysql::quote(AbstractSession.marshalize(data))}')")
new_session.id = connection.insert_id
end
new_session
end
# delete all sessions meeting a given +condition+. it is the
# caller's responsibility to pass a valid sql condition
def delete_all(condition=nil)
if condition
session_connection.query("DELETE FROM sessions WHERE #{condition}")
else
session_connection.query("DELETE FROM sessions")
end
end
end # class methods
# update session with given +data+.
# unlike the default implementation using ActiveRecord, updating of
# column `updated_at` will be done by the datbase itself
def update_session(data)
connection = self.class.session_connection
if @id
# if @id is not nil, this is a session already stored in the database
# update the relevant field using @id as key
connection.query("UPDATE sessions SET `updated_at`=NOW(), `data`='#{Mysql::quote(AbstractSession.marshalize(data))}' WHERE id=#{@id}")
else
# if @id is nil, we need to create a new session in the database
# and set @id to the primary key of the inserted record
connection.query("INSERT INTO sessions (`created_at`, `updated_at`, `session_id`, `data`) VALUES (NOW(), NOW(), '#{@session_id}', '#{Mysql::quote(AbstractSession.marshalize(data))}')")
@id = connection.insert_id
end
end
# destroy the current session
def destroy
self.class.delete_all("session_id='#{session_id}'")
end
end
__END__
# This software is released under the MIT license
#
# Copyright (c) 2005,2006 Stefan Kaes
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,152 +0,0 @@
require 'oci8'
# OracleSession is a down to the bare metal session store
# implementation to be used with +SQLSessionStore+. It is much faster
# than the default ActiveRecord implementation.
#
# The implementation assumes that the table column names are 'id',
# 'session_id', 'data', 'created_at' and 'updated_at'. If you want use
# other names, you will need to change the SQL statments in the code.
#
# This table layout is compatible with ActiveRecordStore.
class OracleSession < AbstractSession
class << self
# try to find a session with a given +session_id+. returns nil if
# no such session exists. note that we don't retrieve
# +created_at+ and +updated_at+ as they are not accessed anywhyere
# outside this class.
def find_session(session_id)
new_session = nil
# Make sure to save the @id if we find an existing session
cursor = session_connection.exec(find_session_sql, session_id)
if row = cursor.fetch_hash
new_session = new(session_id, unmarshalize(row['DATA'].read), row['ID'])
# Pull out native columns
native_columns.each do |col|
new_session.data[col] = row[col.to_s.upcase]
new_session.data[col] = row[col.to_s.upcase]
end
end
cursor.close
new_session
end
# create a new session with given +session_id+ and +data+
# and save it immediately to the database
def create_session(session_id, data={})
new_session = new(session_id, data)
if eager_session_creation
new_session.id = next_id
cursor = session_connection.parse(insert_session_sql)
# Now bind all variables
cursor.bind_param(':id', new_session.id)
cursor.bind_param(':session_id', session_id)
native_columns.each do |col|
cursor.bind_param(":#{col}", data.delete(col) || '')
end
cursor.bind_param(':data', marshalize(data))
cursor.exec
cursor.close
end
new_session
end
# Internal methods for generating SQL
# Get the next ID from the sequence
def next_id
cursor = session_connection.exec("SELECT #{table_name}_seq.nextval FROM dual")
id = cursor.fetch.first.to_i
cursor.close
id
end
# Dynamically generate finder SQL so we can include our special columns
def find_session_sql
@find_session_sql ||=
"SELECT " + ([:id, :data] + native_columns).join(', ') +
" FROM #{table_name} WHERE session_id = :session_id AND rownum = 1"
end
def insert_session_sql
@insert_session_sql ||=
"INSERT INTO #{table_name} (" + ([:id, :data, :session_id] + native_columns + [:created_at, :updated_at]).join(', ') + ")" +
" VALUES (" + ([:id, :data, :session_id] + native_columns).collect{|col| ":#{col}" }.join(', ') +
" , SYSDATE, SYSDATE)"
end
def update_session_sql
@update_session_sql ||=
"UPDATE #{table_name} SET "+
([:data] + native_columns).collect{|col| "#{col} = :#{col}"}.join(', ') +
" , updated_at = SYSDATE WHERE ID = :id"
end
end # class methods
# update session with given +data+.
# unlike the default implementation using ActiveRecord, updating of
# column `updated_at` will be done by the database itself
def update_session(data)
connection = self.class.session_connection
cursor = nil
if @id
# if @id is not nil, this is a session already stored in the database
# update the relevant field using @id as key
cursor = connection.parse(self.class.update_session_sql)
else
# if @id is nil, we need to create a new session in the database
# and set @id to the primary key of the inserted record
@id = self.class.next_id
cursor = connection.parse(self.class.insert_session_sql)
cursor.bind_param(':session_id', @session_id)
end
# These are always the same, as @id is set above!
cursor.bind_param(':id', @id, Fixnum)
native_columns.each do |col|
cursor.bind_param(":#{col}", data.delete(col) || '')
end
cursor.bind_param(':data', self.class.marshalize(data))
cursor.exec
cursor.close
end
# destroy the current session
def destroy
self.class.delete_all(["session_id = ?", session_id])
end
end
__END__
# This software is released under the MIT license
#
# Copyright (c) 2006 Stefan Kaes
# Copyright (c) 2006 Tiago Macedo
# Copyright (c) 2007 Nate Wiger
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,105 +0,0 @@
require 'pg'
# PostgresqlSession is a down to the bare metal session store
# implementation to be used with +SQLSessionStore+. It is much faster
# than the default ActiveRecord implementation.
#
# The implementation assumes that the table column names are 'id',
# 'session_id', 'data', 'created_at' and 'updated_at'. If you want use
# other names, you will need to change the SQL statments in the code.
#
# This table layout is compatible with ActiveRecordStore.
class PostgresqlSession < AbstractSession
class << self
# try to find a session with a given +session_id+. returns nil if
# no such session exists. note that we don't retrieve
# +created_at+ and +updated_at+ as they are not accessed anywhyere
# outside this class.
def find_session(session_id)
connection = session_connection
result = connection.query("SELECT id, data FROM sessions WHERE session_id = $1 LIMIT 1", [session_id])
if result.ntuples > 0
my_session = new(session_id, AbstractSession.unmarshalize(result.getvalue(0, 1)))
my_session.id = result.getvalue(0, 0)
else
my_session = nil
end
result.clear
my_session
end
# create a new session with given +session_id+ and +data+
# and save it immediately to the database
def create_session(session_id, data={})
new_session = new(session_id, data)
if @@eager_session_creation
connection = session_connection
connection.query("INSERT INTO sessions (created_at, updated_at, session_id, data) VALUES (NOW(), NOW(), $1, $2)", [session_id, AbstractSession.marshalize(data)])
new_session.id = connection.lastval
end
new_session
end
# delete all sessions meeting a given +condition+. it is the
# caller's responsibility to pass a valid sql condition
def delete_all(condition=nil)
if condition
session_connection.query("DELETE FROM sessions WHERE #{condition}")
else
session_connection.query("DELETE FROM sessions")
end
end
end # class methods
# update session with given +data+.
# unlike the default implementation using ActiveRecord, updating of
# column `updated_at` will be done by the database itself
def update_session(data)
connection = self.class.session_connection
if @id
# if @id is not nil, this is a session already stored in the database
# update the relevant field using @id as key
connection.query("UPDATE sessions SET updated_at = NOW(), data = $1 WHERE id = $2", [AbstractSession.marshalize(data), @id])
else
# if @id is nil, we need to create a new session in the database
# and set @id to the primary key of the inserted record
result = connection.query("INSERT INTO sessions (created_at, updated_at, session_id, data) VALUES (NOW(), NOW(), $1, $2) RETURNING id", [@session_id, AbstractSession.marshalize(data)])
@id = result.getvalue(0, 0)
result.clear
end
end
# destroy the current session
def destroy
self.class.delete_all("session_id='#{session_id}'")
end
end
__END__
# This software is released under the MIT license
#
# Copyright (c) 2006 Stefan Kaes
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,27 +0,0 @@
# An ActiveRecord class which corresponds to the database table
# +sessions+. Functions +find_session+, +create_session+,
# +update_session+ and +destroy+ constitute the interface to class
# +SqlSessionStore+.
class SqlSession < ActiveRecord::Base
# this class should not be reloaded
def self.reloadable?
false
end
# retrieve session data for a given +session_id+ from the database,
# return nil if no such session exists
def self.find_session(session_id)
find :first, :conditions => { :session_id => session_id }
end
# create a new session with given +session_id+ and +data+
def self.create_session(session_id, data)
new(:session_id => session_id, :data => data)
end
# update session data and store it in the database
def update_session(data)
update_attribute('data', data)
end
end

View file

@ -1,157 +0,0 @@
require 'base64'
# +SqlSessionStore+ is a stripped down, optimized for speed version of
# class +ActiveRecordStore+.
# Hack for older versions of Rails
unless defined?(ActionController::Session::AbstractStore)
module ActionController
module Session
class AbstractStore
end
end
end
end
class SqlSessionStore < ActionController::Session::AbstractStore
# The class to be used for creating, retrieving and updating sessions.
# Defaults to SqlSessionStore::SqlSession, which is derived from +ActiveRecord::Base+.
#
# In order to achieve acceptable performance you should implement
# your own session class, similar to the one provided for Myqsl.
#
# Only functions +find_session+, +create_session+,
# +update_session+ and +destroy+ are required. The best implementations
# are +postgresql_session.rb+ and +oracle_session.rb+.
cattr_accessor :session_class
self.session_class = SqlSession
# Rack-ism for Rails 2.3.0
SESSION_RECORD_KEY = 'rack.session.record'.freeze
# Backwards-compat indicators (booleans for speed)
cattr_accessor :use_rack_session, :use_cgi_session
self.use_rack_session = false
self.use_cgi_session = false
# For Rack compatibility (Rails 2.3.0+)
def get_session(env, sid)
sid ||= generate_sid
#puts "get_session(#{sid})"
session = find_or_create_session(sid)
env[SESSION_RECORD_KEY] = session
[sid, session.data]
end
# For Rack compatibility (Rails 2.3.0+)
def set_session(env, sid, session_data)
#puts "set_session(#{sid})"
session = env[SESSION_RECORD_KEY]
session.update_session(session_data)
return true # indicate ok to Rack
end
# Create a new SqlSessionStore instance. This method hooks into
# the find/create methods of a given driver class.
#
# +session_id+ is the session ID for which this instance is being created.
def find_or_create_session(session_id)
if @session = session_class.find_session(session_id)
@data = @session.data
else
@session = session_class.create_session(session_id)
@data = {}
end
@session
end
# Below here is for pre-Rails 2.3.0 and not used in Rack-based servers
# The CGI::Session methods are a bit odd in that half are class and half
# are instance-based methods
# Note that +option+ is currently ignored as no options are recognized.
def initialize(session, options={})
# This is just some optimization since this is called over and over and over
if self.use_rack_session
super # MUST call super for Rack sessions
return true
elsif self.use_cgi_session
find_or_create_session(session.session_id)
else
version ||= Rails.version.split('.')
if version[0].to_i == 2 && version[1].to_i < 3
find_or_create_session(session.session_id)
self.use_cgi_session = true
else
super # MUST call super for Rack sessions
self.use_rack_session = true
end
end
end
# Update the database and disassociate the session object
def close
if @session
@session.update_session(@data)
@session = nil
end
end
# Delete the current session, disassociate and destroy session object
def delete
if @session
@session.destroy
@session = nil
end
end
# Restore session data from the session object
def restore
if @session
@data = @session.data
end
end
# Save session data in the session object
def update
if @session
@session.update_session(@data)
end
end
def id
@session.id
end
end
class CGI::Session
def id
@dbman.id
end
end
__END__
# This software is released under the MIT license
#
# Copyright (c) 2008, 2009 Nate Wiger
# Copyright (c) 2005, 2006 Stefan Kaes
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,105 +0,0 @@
require 'sqlite3'
# SqliteSession is a down to the bare metal session store
# implementation to be used with +SQLSessionStore+. It is much faster
# than the default ActiveRecord implementation.
#
# The implementation assumes that the table column names are 'id',
# 'data', 'created_at' and 'updated_at'. If you want use other names,
# you will need to change the SQL statments in the code.
class SqliteSession < AbstractSession
class << self
# try to find a session with a given +session_id+. returns nil if
# no such session exists. note that we don't retrieve
# +created_at+ and +updated_at+ as they are not accessed anywhyere
# outside this class
def find_session(session_id)
connection = session_connection
result = connection.execute("SELECT id, data FROM sessions WHERE `session_id`='#{session_id}' LIMIT 1")
my_session = nil
# each is used below, as other methods barf on my 64bit linux machine
# I suspect this to be a bug in sqlite-ruby
result.each do |row|
my_session = new(session_id, row[1])
my_session.id = row[0]
end
# result.free
my_session
end
# create a new session with given +session_id+ and +data+
# and save it immediately to the database
def create_session(session_id, data)
new_session = new(session_id, data)
if @@eager_session_creation
connection = session_connection
connection.execute("INSERT INTO sessions ('id', `created_at`, `updated_at`, `session_id`, `data`) VALUES (NULL, datetime('now'), datetime('now'), '#{session_id}', '#{SQLite3::Database.quote(data)}')")
new_session.id = connection.last_insert_row_id()
end
new_session
end
# delete all sessions meeting a given +condition+. it is the
# caller's responsibility to pass a valid sql condition
def delete_all(condition=nil)
if condition
session_connection.execute("DELETE FROM sessions WHERE #{condition}")
else
session_connection.execute("DELETE FROM sessions")
end
end
end # class methods
# update session with given +data+.
# unlike the default implementation using ActiveRecord, updating of
# column `updated_at` will be done by the database itself
def update_session(data)
connection = SqlSession.connection.instance_variable_get(:@connection) #self.class.session_connection
if @id
# if @id is not nil, this is a session already stored in the database
# update the relevant field using @id as key
connection.execute("UPDATE sessions SET `updated_at`=datetime('now'), `data`='#{SQLite3::Database.quote(data)}' WHERE id=#{@id}")
else
# if @id is nil, we need to create a new session in the database
# and set @id to the primary key of the inserted record
connection.execute("INSERT INTO sessions ('id', `created_at`, `updated_at`, `session_id`, `data`) VALUES (NULL, datetime('now'), datetime('now'), '#{@session_id}', '#{SQLite3::Database.quote(data)}')")
@id = connection.last_insert_row_id()
end
end
# destroy the current session
def destroy
connection = SqlSession.connection.instance_variable_get(:@connection)
connection.execute("delete from sessions where session_id='#{session_id}'")
end
end
__END__
# This software is released under the MIT license
#
# Copyright (c) 2005, 2006 Stefan Kaes
# Copyright (c) 2006 Ted X Toth
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.