Updating to use Rails 2.1.2. Moving the gem dependancies to the config/environment.rb file. Moving the vendor/plugins externals into our svn.

This commit is contained in:
Shaun McDonald 2008-10-28 20:42:48 +00:00
parent 38f4e17865
commit 252c2f7022
46 changed files with 3919 additions and 7 deletions

View file

@ -0,0 +1,20 @@
Copyright (c) 2006-2008 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.

60
vendor/plugins/sql_session_store/README vendored Executable file
View file

@ -0,0 +1,60 @@
== SqlSessionStore
See http://railsexpress.de/blog/articles/2005/12/19/roll-your-own-sql-session-store
Only Mysql, Postgres 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 migrate
or
rake db:migrate
for edge rails.
== Step 2
Add the code below after the initializer config section:
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.
update(:database_manager => SqlSessionStore)
Finally, 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
== 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

22
vendor/plugins/sql_session_store/Rakefile vendored Executable file
View file

@ -0,0 +1,22 @@
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

@ -0,0 +1,17 @@
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

@ -0,0 +1,25 @@
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

@ -0,0 +1,38 @@
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

1
vendor/plugins/sql_session_store/init.rb vendored Executable file
View file

@ -0,0 +1 @@
require 'sql_session_store'

2
vendor/plugins/sql_session_store/install.rb vendored Executable file
View file

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

View file

@ -0,0 +1,132 @@
require 'mysql'
# allow access to the real Mysql connection
class ActiveRecord::ConnectionAdapters::MysqlAdapter
attr_reader :connection
end
# 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
# 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
attr_accessor :id, :session_id, :data
def initialize(session_id, data)
@session_id = session_id
@data = data
@id = nil
end
class << self
# retrieve the session table connection and get the 'raw' Mysql connection from it
def session_connection
SqlSession.connection.connection
end
# 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
session_id = Mysql::quote(session_id)
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, 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)
session_id = Mysql::quote(session_id)
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(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(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(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-2008 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

@ -0,0 +1,143 @@
require 'oci8'
# allow access to the real Oracle connection
class ActiveRecord::ConnectionAdapters::OracleAdapter
attr_reader :connection
end
# 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
# if you need Rails components, and you have a pages which create
# new sessions, and embed components insides these pages that need
# session access, then you *must* set +eager_session_creation+ to
# true (as of Rails 1.0). Not needed for Rails 1.1 and up.
cattr_accessor :eager_session_creation
@@eager_session_creation = false
attr_accessor :id, :session_id, :data
def initialize(session_id, data)
@session_id = session_id
@data = data
@id = nil
end
class << self
# retrieve the session table connection and get the 'raw' Oracle connection from it
def session_connection
SqlSession.connection.connection
end
# 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
connection = session_connection
result = connection.exec("SELECT id, data FROM sessions WHERE session_id = :a and rownum=1", session_id)
# Make sure to save the @id if we find an existing session
while row = result.fetch
new_session = new(session_id,row[1].read)
new_session.id = row[0]
end
result.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
connection = session_connection
connection.exec("INSERT INTO sessions (id, created_at, updated_at, session_id, data)"+
" VALUES (sessions_seq.nextval, SYSDATE, SYSDATE, :a, :b)",
session_id, data)
result = connection.exec("SELECT sessions_seq.currval FROM dual")
row = result.fetch
new_session.id = row[0].to_i
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.exec("DELETE FROM sessions WHERE #{condition}")
else
session_connection.exec("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.exec("UPDATE sessions SET updated_at = SYSDATE, data = :a WHERE id = :b",
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
connection.exec("INSERT INTO sessions (id, created_at, updated_at, session_id, data)"+
" VALUES (sessions_seq.nextval, SYSDATE, SYSDATE, :a, :b)",
@session_id, data)
result = connection.exec("SELECT sessions_seq.currval FROM dual")
row = result.fetch
@id = row[0].to_i
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-2008 Stefan Kaes
# Copyright (c) 2006-2008 Tiago Macedo
# Copyright (c) 2007-2008 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

@ -0,0 +1,136 @@
require 'postgres'
# allow access to the real Mysql connection
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
attr_reader :connection
end
# 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
# if you need Rails components, and you have a pages which create
# new sessions, and embed components insides these pages that need
# session access, then you *must* set +eager_session_creation+ to
# true (as of Rails 1.0). Not needed for Rails 1.1 and up.
cattr_accessor :eager_session_creation
@@eager_session_creation = false
attr_accessor :id, :session_id, :data
def initialize(session_id, data)
@session_id = session_id
@data = data
@id = nil
end
class << self
# retrieve the session table connection and get the 'raw' Postgresql connection from it
def session_connection
SqlSession.connection.connection
end
# 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
# postgres adds string delimiters when quoting, so strip them off
session_id = PGconn::quote(session_id)[1..-2]
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, row[1])
my_session.id = row[0]
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)
# postgres adds string delimiters when quoting, so strip them off
session_id = PGconn::quote(session_id)[1..-2]
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}', #{PGconn::quote(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\"=#{PGconn::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.query("INSERT INTO sessions (\"created_at\", \"updated_at\", \"session_id\", \"data\") VALUES (NOW(), NOW(), '#{@session_id}', #{PGconn::quote(data)})")
@id = connection.lastval rescue connection.query("select lastval()").first[0]
end
end
# destroy the current session
def destroy
self.class.delete_all("session_id=#{PGconn.quote(session_id)}")
end
end
__END__
# This software is released under the MIT license
#
# Copyright (c) 2006-2008 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

@ -0,0 +1,27 @@
# 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

@ -0,0 +1,116 @@
require 'active_record'
require 'cgi'
require 'cgi/session'
begin
require 'base64'
rescue LoadError
end
# +SqlSessionStore+ is a stripped down, optimized for speed version of
# class +ActiveRecordStore+.
class SqlSessionStore
# The class to be used for creating, retrieving and updating sessions.
# Defaults to SqlSessionStore::Session, 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. See file +mysql_session.rb+.
cattr_accessor :session_class
@@session_class = SqlSession
# Create a new SqlSessionStore instance.
#
# +session+ is the session for which this instance is being created.
#
# +option+ is currently ignored as no options are recognized.
def initialize(session, option=nil)
if @session = @@session_class.find_session(session.session_id)
@data = unmarshalize(@session.data)
else
@session = @@session_class.create_session(session.session_id, marshalize({}))
@data = {}
end
end
# Update the database and disassociate the session object
def close
if @session
@session.update_session(marshalize(@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 = unmarshalize(@session.data)
end
end
# Save session data in the session object
def update
if @session
@session.update_session(marshalize(@data))
end
end
private
if defined?(Base64)
def unmarshalize(data)
Marshal.load(Base64.decode64(data))
end
def marshalize(data)
Base64.encode64(Marshal.dump(data))
end
else
def unmarshalize(data)
Marshal.load(data.unpack("m").first)
end
def marshalize(data)
[Marshal.dump(data)].pack("m")
end
end
end
__END__
# This software is released under the MIT license
#
# Copyright (c) 2005-2008 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

@ -0,0 +1,133 @@
require 'sqlite3'
# allow access to the real Sqlite connection
#class ActiveRecord::ConnectionAdapters::SQLiteAdapter
# attr_reader :connection
#end
# 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
# 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
attr_accessor :id, :session_id, :data
def initialize(session_id, data)
@session_id = session_id
@data = data
@id = nil
end
class << self
# retrieve the session table connection and get the 'raw' Sqlite connection from it
def session_connection
SqlSession.connection.instance_variable_get(:@connection)
end
# 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
session_id = SQLite3::Database.quote(session_id)
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)
session_id = SQLite3::Database.quote(session_id)
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-2008 Stefan Kaes
# Copyright (c) 2006-2008 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.