lib/active_record/session_store.rb



require 'active_record'
require 'active_record/session_store/version'
require 'action_dispatch/session/active_record_store'
require "active_record/session_store/extension/logger_silencer"
require 'active_support/core_ext/hash/keys'
require 'multi_json'

module ActiveRecord
  module SessionStore
    module ClassMethods # :nodoc:
      mattr_accessor :serializer

      def serialize(data)
        serializer_class.dump(data) if data
      end

      def deserialize(data)
        serializer_class.load(data) if data
      end

      def drop_table!
        if connection.schema_cache.respond_to?(:clear_data_source_cache!)
          connection.schema_cache.clear_data_source_cache!(table_name)
        else
          connection.schema_cache.clear_table_cache!(table_name)
        end
        connection.drop_table table_name
      end

      def create_table!
        if connection.schema_cache.respond_to?(:clear_data_source_cache!)
          connection.schema_cache.clear_data_source_cache!(table_name)
        else
          connection.schema_cache.clear_table_cache!(table_name)
        end
        connection.create_table(table_name) do |t|
          t.string session_id_column, :limit => 255
          t.text data_column_name
        end
        connection.add_index table_name, session_id_column, :unique => true
      end

      def serializer_class
        case self.serializer
          when :marshal, nil then
            MarshalSerializer
          when :json then
            JsonSerializer
          when :hybrid then
            HybridSerializer
          when :null then
            NullSerializer
          else
            self.serializer
        end
      end

      # Use Marshal with Base64 encoding
      class MarshalSerializer
        def self.load(value)
          Marshal.load(::Base64.decode64(value))
        end

        def self.dump(value)
          ::Base64.encode64(Marshal.dump(value))
        end
      end

      # Uses built-in JSON library to encode/decode session
      class JsonSerializer
        def self.load(value)
          hash = MultiJson.load(value)
          hash.is_a?(Hash) ? hash.with_indifferent_access[:value] : hash
        end

        def self.dump(value)
          MultiJson.dump(value: value)
        end
      end

      # Transparently migrates existing session values from Marshal to JSON
      class HybridSerializer < JsonSerializer
        MARSHAL_SIGNATURE = 'BAh'.freeze

        def self.load(value)
          if needs_migration?(value)
            Marshal.load(::Base64.decode64(value))
          else
            super
          end
        end

        def self.needs_migration?(value)
          value.start_with?(MARSHAL_SIGNATURE)
        end
      end

      # Defer serialization to the ActiveRecord database adapter
      class NullSerializer
        def self.load(value)
          value
        end

        def self.dump(value)
          value
        end
      end
    end
  end
end

ActiveSupport.on_load(:active_record) do
  require 'active_record/session_store/session'
  ActionDispatch::Session::ActiveRecordStore.session_class = ActiveRecord::SessionStore::Session
end

require 'active_record/session_store/sql_bypass'
require 'active_record/session_store/railtie' if defined?(Rails)

Logger.send :include, ActiveRecord::SessionStore::Extension::LoggerSilencer

begin
  require "syslog/logger"
  Syslog::Logger.send :include, ActiveRecord::SessionStore::Extension::LoggerSilencer
rescue LoadError; end