Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Place me in initializers
- # Configure the database connection
- #
- require 'sequel'
- module Rails
- class SessionStore < ActionDispatch::Session::AbstractStore
- module ClassMethods # :nodoc:
- def marshal(data)
- ::Base64.encode64(Marshal.dump(data)) if data
- end
- def unmarshal(data)
- Marshal.load(::Base64.decode64(data)) if data
- end
- end
- # A barebones session store which duck-types with the default session
- # store but bypasses Active Record and issues SQL directly. This is
- # an example session model class meant as a basis for your own classes.
- #
- # The database connection, table name, and session id and data columns
- # are configurable class attributes. Marshaling and unmarshaling
- # are implemented as class methods that you may override. By default,
- # marshaling data is
- #
- # ::Base64.encode64(Marshal.dump(data))
- #
- # and unmarshaling data is
- #
- # Marshal.load(::Base64.decode64(data))
- #
- # This marshaling behavior is intended to store the widest range of
- # binary session data in a +text+ column. For higher performance,
- # store in a +blob+ column instead and forgo the Base64 encoding.
- class SqlBypass
- extend ClassMethods
- ##
- # :singleton-method:
- # The table name defaults to 'sessions'.
- cattr_accessor :table_name
- @@table_name = 'sessions'
- ##
- # :singleton-method:
- # The session id field defaults to 'session_id'.
- cattr_accessor :session_id_column
- @@session_id_column = 'session_id'
- ##
- # :singleton-method:
- # The data field defaults to 'data'.
- cattr_accessor :data_column
- @@data_column = 'data'
- class << self
- alias :data_column_name :data_column
- attr_writer :connection
- attr_writer :connection_pool # Is this needed?
- def connection
- @connection ||= ::Sequel.connect(:adapter=>'postgres', :host=>'localhost', :database=>'xxx', :user=>'xxx', :password=>'xxx')
- end
- # def connection_pool
- # @connection_pool ||= ::Sequel.connect(:adapter=>'postgres', :host=>'localhost', :database=>'', :user=>'', :password=>'')
- # end
- # Look up a session by id and unmarshal its data if found.
- def find_by_session_id(session_id)
- record = connection.fetch("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}='#{session_id}'").first
- # debugger
- if !record.nil?
- new(:session_id => session_id, :marshaled_data => record[:data])
- end
- end
- end
- delegate :connection, :connection=, :connection_pool, :connection_pool=, :to => self
- attr_reader :session_id, :new_record
- alias :new_record? :new_record
- attr_writer :data
- # Look for normal and marshaled data, self.find_by_session_id's way of
- # telling us to postpone unmarshaling until the data is requested.
- # We need to handle a normal data attribute in case of a new record.
- def initialize(attributes)
- @session_id = attributes[:session_id]
- @data = attributes[:data]
- @marshaled_data = attributes[:marshaled_data]
- @new_record = @marshaled_data.nil?
- end
- # Lazy-unmarshal session state.
- def data
- unless @data
- if @marshaled_data
- @data, @marshaled_data = self.class.unmarshal(@marshaled_data) || {}, nil
- else
- @data = {}
- end
- end
- @data
- end
- def loaded?
- @data
- end
- def save
- return false unless loaded?
- marshaled_data = self.class.marshal(data)
- connect = connection
- if @new_record
- @new_record = false
- connect << "INSERT INTO #{table_name} (#{session_id_column}, #{data_column}) VALUES ('#{session_id}', '#{marshaled_data}')"
- else
- connect << "UPDATE #{table_name} SET #{data_column}='#{marshaled_data}' WHERE #{session_id_column}='#{session_id}'"
- end
- end
- def destroy
- return if @new_record
- connect = connection
- connect << "DELETE FROM #{table_name} WHERE #{session_id_column}='#{session_id}'"
- end
- end
- # The class used for session storage.
- cattr_accessor :session_class
- self.session_class = SqlBypass
- SESSION_RECORD_KEY = 'rack.session.record'
- ENV_SESSION_OPTIONS_KEY = ::Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY
- private
- def get_session(env, sid)
- # Base.silence do
- unless sid and session = @@session_class.find_by_session_id(sid)
- # If the sid was nil or if there is no pre-existing session under the sid,
- # force the generation of a new sid and associate a new session associated with the new sid
- sid = generate_sid
- session = @@session_class.new(:session_id => sid, :data => {})
- end
- env[SESSION_RECORD_KEY] = session
- [sid, session.data]
- # end
- end
- def set_session(env, sid, session_data, options)
- # Base.silence do
- record = get_session_model(env, sid)
- record.data = session_data
- return false unless record.save
- session_data = record.data
- if session_data && session_data.respond_to?(:each_value)
- session_data.each_value do |obj|
- obj.clear_association_cache if obj.respond_to?(:clear_association_cache)
- end
- end
- # end
- sid
- end
- def destroy_session(env, session_id, options)
- if sid = current_session_id(env)
- # Base.silence do
- get_session_model(env, sid).destroy
- env[SESSION_RECORD_KEY] = nil
- # end
- end
- generate_sid unless options[:drop]
- end
- def get_session_model(env, sid)
- if env[ENV_SESSION_OPTIONS_KEY][:id].nil?
- env[SESSION_RECORD_KEY] = find_session(sid)
- else
- env[SESSION_RECORD_KEY] ||= find_session(sid)
- end
- end
- def find_session(id)
- @@session_class.find_by_session_id(id) ||
- @@session_class.new(:session_id => id, :data => {})
- end
- end
- end
Add Comment
Please, Sign In to add comment