1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/actionpack/lib/action_dispatch/request/session.rb
Aaron Patterson 3692ca5ce7 don't hold a reference to env in the options object
I want to decouple Rails from the rack ENV as much as possible.  We
should try to keep as few references to the env as possible
2015-06-13 14:12:44 -07:00

225 lines
5.4 KiB
Ruby
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

require 'rack/session/abstract/id'
module ActionDispatch
class Request < Rack::Request
# Session is responsible for lazily loading the session from store.
class Session # :nodoc:
ENV_SESSION_KEY = Rack::Session::Abstract::ENV_SESSION_KEY # :nodoc:
ENV_SESSION_OPTIONS_KEY = Rack::Session::Abstract::ENV_SESSION_OPTIONS_KEY # :nodoc:
# Singleton object used to determine if an optional param wasn't specified
Unspecified = Object.new
# Creates a session hash, merging the properties of the previous session if any
def self.create(store, env, default_options)
session_was = find env
session = Request::Session.new(store, env)
session.merge! session_was if session_was
set(env, session)
Options.set(env, Request::Session::Options.new(store, default_options))
session
end
def self.find(env)
env[ENV_SESSION_KEY]
end
def self.set(env, session)
env[ENV_SESSION_KEY] = session
end
class Options #:nodoc:
def self.set(env, options)
env[ENV_SESSION_OPTIONS_KEY] = options
end
def self.find(env)
env[ENV_SESSION_OPTIONS_KEY]
end
def initialize(by, default_options)
@by = by
@delegate = default_options.dup
end
def [](key)
@delegate[key]
end
def id(env)
@delegate.fetch(:id) {
@by.send(:extract_session_id, env)
}
end
def []=(k,v); @delegate[k] = v; end
def to_hash; @delegate.dup; end
def values_at(*args); @delegate.values_at(*args); end
end
def initialize(by, env)
@by = by
@env = env
@delegate = {}
@loaded = false
@exists = nil # we haven't checked yet
end
def id
options.id(@env)
end
def options
Options.find @env
end
def destroy
clear
options = self.options || {}
@by.send(:destroy_session, @env, options.id(@env), options)
# Load the new sid to be written with the response
@loaded = false
load_for_write!
end
# Returns value of the key stored in the session or
# nil if the given key is not found in the session.
def [](key)
load_for_read!
@delegate[key.to_s]
end
# Returns true if the session has the given key or false.
def has_key?(key)
load_for_read!
@delegate.key?(key.to_s)
end
alias :key? :has_key?
alias :include? :has_key?
# Returns keys of the session as Array.
def keys
@delegate.keys
end
# Returns values of the session as Array.
def values
@delegate.values
end
# Writes given value to given key of the session.
def []=(key, value)
load_for_write!
@delegate[key.to_s] = value
end
# Clears the session.
def clear
load_for_write!
@delegate.clear
end
# Returns the session as Hash.
def to_hash
load_for_read!
@delegate.dup.delete_if { |_,v| v.nil? }
end
# Updates the session with given Hash.
#
# session.to_hash
# # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2"}
#
# session.update({ "foo" => "bar" })
# # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
#
# session.to_hash
# # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
def update(hash)
load_for_write!
@delegate.update stringify_keys(hash)
end
# Deletes given key from the session.
def delete(key)
load_for_write!
@delegate.delete key.to_s
end
# Returns value of given key from the session, or raises +KeyError+
# if can't find given key in case of not setted dafault value.
# Returns default value if specified.
#
# session.fetch(:foo)
# # => KeyError: key not found: "foo"
#
# session.fetch(:foo, :bar)
# # => :bar
#
# session.fetch(:foo) do
# :bar
# end
# # => :bar
def fetch(key, default=Unspecified, &block)
load_for_read!
if default == Unspecified
@delegate.fetch(key.to_s, &block)
else
@delegate.fetch(key.to_s, default, &block)
end
end
def inspect
if loaded?
super
else
"#<#{self.class}:0x#{(object_id << 1).to_s(16)} not yet loaded>"
end
end
def exists?
return @exists unless @exists.nil?
@exists = @by.send(:session_exists?, @env)
end
def loaded?
@loaded
end
def empty?
load_for_read!
@delegate.empty?
end
def merge!(other)
load_for_write!
@delegate.merge!(other)
end
private
def load_for_read!
load! if !loaded? && exists?
end
def load_for_write!
load! unless loaded?
end
def load!
id, session = @by.load_session @env
options[:id] = id
@delegate.replace(stringify_keys(session))
@loaded = true
end
def stringify_keys(other)
other.each_with_object({}) { |(key, value), hash|
hash[key.to_s] = value
}
end
end
end
end