Skip to content

Commit

Permalink
Rails 2.3 compat (retains backwards compatibility with 2.2 and prior)
Browse files Browse the repository at this point in the history
  • Loading branch information
fcheung committed Mar 25, 2009
1 parent 67db729 commit 8c80d09
Show file tree
Hide file tree
Showing 25 changed files with 400 additions and 278 deletions.
2 changes: 1 addition & 1 deletion LICENSE
@@ -1,4 +1,4 @@
Copyright (c) 2007 Frederick Cheung
Copyright (c) 2007-2009 Frederick Cheung
Copyright (c) 2006 Dr.-Ing. Stefan Kaes

Permission is hereby granted, free of charge, to any person obtaining
Expand Down
9 changes: 8 additions & 1 deletion init.rb
@@ -1 +1,8 @@
require 'smart_session_store'
version ||= Rails.version.split('.')

if version[0].to_i == 2 && version[1].to_i < 3 #version prior to 2.3 use the legacy store
require 'legacy_smart_session_sore'
SmartSessionStore = LegacySmartSessionStore
else
require 'smart_session_store'
end
105 changes: 105 additions & 0 deletions lib/legacy_smart_session_store.rb
@@ -0,0 +1,105 @@
require 'active_record'
require 'cgi'
require 'cgi/session'
require 'base64'
require 'pp'
# +SmartSessionStore+ is a session store that strives to correctly handle session storage in the face of multiple
# concurrent actions accessing the session. It is derived from Stephen Kaes' +SqlSessionStore+, a stripped down,
# optimized for speed version of class +ActiveRecordStore+.
#
# LegacySmartSessionStore implements the session store interface used by versions of rails prior to 2.3
class LegacySmartSessionStore
include SessionSmarts
# The class to be used for creating, retrieving and updating sessions.
# Defaults to SmartSessionStore::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 SmartSessionStore 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)
self.data = unmarshalize(@session.data)
else
@session = @@session_class.create_session(session.session_id, marshalize({}))
self.data = {}
end
end

# Update the database and disassociate the session object
def close
if @session
finalize_session
@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
self.data = unmarshalize(@session.data)
end
end

# Save session data in the session object
def update
if @session
finalize_session
end
end

private

def data= data
@data = data
end

def finalize_session
@data, @session = save_session(@session, @data || {})
end
end

__END__

# This software is released under the MIT license
# Copyright (c) 2007 Frederick Cheung
# 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.

File renamed without changes.
54 changes: 54 additions & 0 deletions lib/session_smarts.rb
@@ -0,0 +1,54 @@
module SessionSmarts
def marshalize(data)
Base64.encode64(Marshal.dump(data))
end

def unmarshalize(data)
Marshal.load(Base64.decode64(data))
end

def save_session(session, data)
original_data = unmarshalize(session.data)
original_marshalled_data = session.data

deleted_keys = original_data.keys - data.keys
changed_keys = []
data.each {|k,v| changed_keys << k if Marshal.dump( original_data[k]) != Marshal.dump( v)}

return nil if changed_keys.empty? && deleted_keys.empty?

SqlSession.transaction do
fresh_session = session_class.find_session(session.session_id, true)
if fresh_session && fresh_session.data != original_marshalled_data && fresh_data = unmarshalize(fresh_session.data)
deleted_keys.each {|k| fresh_data.delete k}
changed_keys.each {|k| fresh_data[k] = data[k]}
data = fresh_data
session = fresh_session
end
session.update_session(marshalize(data))
end
return data, session
end
end

# This software is released under the MIT license
# Copyright (c) 2007-2009 Frederick Cheung

# 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.
112 changes: 25 additions & 87 deletions lib/smart_session_store.rb
@@ -1,14 +1,14 @@
require 'active_record'
require 'cgi'
require 'cgi/session'
require 'base64'
require 'pp'
# +SmartSessionStore+ is a session store that strives to correctly handle session storage in the face of multiple
# concurrent actions accessing the session. It is derived from Stephen Kaes' +SqlSessionStore+, a stripped down,
# optimized for speed version of class +ActiveRecordStore+.

class SmartSessionStore

#
# This version is the one used for rails > 2.3
class SmartSessionStore < ActionController::Session::AbstractStore
include SessionSmarts

# The class to be used for creating, retrieving and updating sessions.
# Defaults to SmartSessionStore::Session, which is derived from +ActiveRecord::Base+.
#
Expand All @@ -21,103 +21,41 @@ class SmartSessionStore
cattr_accessor :session_class
@@session_class = SqlSession

# Create a new SmartSessionStore 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)
self.data = unmarshalize(@session.data)
else
@session = @@session_class.create_session(session.session_id, marshalize({}))
self.data = {}
end
end

# Update the database and disassociate the session object
def close
if @session
save_session
@session = nil
end
end

# Delete the current session, disassociate and destroy session object
def delete
if @session
@session.destroy
@session = nil
SESSION_RECORD_KEY = 'rack.session.record'.freeze

private

def get_session(env, sid)
ActiveRecord::Base.silence do
sid ||= generate_sid
session = find_session(sid)
env[SESSION_RECORD_KEY] = session
[sid, unmarshalize(session.data)]
end
end

# Restore session data from the session object
def restore
if @session
self.data = unmarshalize(@session.data)
end
end
def set_session(env, sid, session_data)
ActiveRecord::Base.silence do
record = env[SESSION_RECORD_KEY] ||= find_session(sid)

# Save session data in the session object
def update
if @session
save_session
data, session = save_session(record, session_data)
env[SESSION_RECORD_KEY] = session
end
end

private

def data= data
@data = data
if @session && @session.data
@original_marshalized_data = @session.data
else
@original_marshalized_data = marshalize( {})
end
@data
end

def unmarshalize(data)
Marshal.load(Base64.decode64(data))
return true
end

def marshalize(data)
Base64.encode64(Marshal.dump(data))
def find_session(id)
@@session_class.find_by_session_id(id) ||
@@session_class.new(:session_id => id, :data => marshalize({}))
end


def save_session
if @original_marshalized_data
@original_data ||= unmarshalize @original_marshalized_data
else
@original_data = {}
end
@data ||= {}

deleted_keys = @original_data.keys - @data.keys
changed_keys = []
@data.each {|k,v| changed_keys << k if Marshal.dump( @original_data[k]) != Marshal.dump( v)}

return if changed_keys.empty? && deleted_keys.empty?

SqlSession.transaction do
fresh_session = @@session_class.find_session(@session.session_id, true)
if fresh_session && fresh_session.data != @original_marshalized_data && fresh_data = unmarshalize(fresh_session.data)
deleted_keys.each {|k| fresh_data.delete k}
changed_keys.each {|k| fresh_data[k] = @data[k]}
@data = fresh_data
@session = fresh_session
end
@session.update_session(marshalize(@data))
end
end
end

__END__

# This software is released under the MIT license
# Copyright (c) 2007 Frederick Cheung
# Copyright (c) 2007-2009 Frederick Cheung
# Copyright (c) 2005,2006 Stefan Kaes

# Permission is hereby granted, free of charge, to any person obtaining
Expand Down
2 changes: 1 addition & 1 deletion test/rails_root/config/database.yml → test/database.yml
Expand Up @@ -7,4 +7,4 @@ mysql:
:host: localhost
:username: smart_session
:password:
:database: smart_session
:database: smart_session
10 changes: 0 additions & 10 deletions test/rails_root/Rakefile

This file was deleted.

4 changes: 0 additions & 4 deletions test/rails_root/app/controllers/application.rb

This file was deleted.

3 changes: 0 additions & 3 deletions test/rails_root/app/helpers/application_helper.rb

This file was deleted.

45 changes: 0 additions & 45 deletions test/rails_root/config/boot.rb

This file was deleted.

0 comments on commit 8c80d09

Please sign in to comment.