Deleting the current session with Rack::Session::Cookie
Just use
session.clear
to destroy the session.
Rack.session cookie not being deleted even after /logout code runs in Sinatra
session.clear
will remove the session vars. You'll still see a session in chrome because it is set by Rack::Session::Cookie middleware after your action has run, but that is just a blank session.
Sinatra/1.4.3 use Rack::Session::Cookie warning
You are using both
enable :sessions
which makes Sinatra setup cookie based sessions, and
use Rack::Session::Cookie, ...
which also adds sessions to your app, so you end up with two instances of Rack::Session::Cookie
in your middleware stack.
The warning is being generated by the session middleware included by Sinatra. By default Sinatra doesn’t create a session secret when running in the development environment (in classic mode at least, it does for modular apps), and so Rack generates the warning in development.
You should only need one of the two ways of enabling sessions, using two together could result in them interacting in unexpected ways.
To avoid the warning, you can explicitly set a secret for the Sinatra session with the session_secret
option:
enable :sessions
set :session_secret, '*&(^B234'
You can also pass the options hash as an argument when enabling sessions. Instead of enable :sessions
, do this:
set :sessions, key: 'N&wedhSDF',
domain: "localhost",
path: '/',
expire_after: 14400,
secret: '*&(^B234'
Rack: Multiple session cookies for a single rack application
In case anyone run with the same needs, I found that making a class to managing sessions inside the application was the easiest way to go.
Rack::Utils have 2 nice shortcuts, Rack::Utils.set_cookie_header! and Utils.delete_cookie_header! that can really make the things easier when dealing with cookies.
I am saving the sessions in the database used my application, but it should be trivial to support another back-end.
As a side note, a few considerations I came with:
- To be sure to the name of the cookie is valid, I am using a sha-1 of the sub-application name for that purpose.
- SecureRandom.urlsafe_base64 is useful for generating session key.
- Sessions cleaning and refreshing has to be implemented manually.
Sample code
The class managing the cookies, the commit function set and delete the cookies to rack.
class Framework::Response::Cookies
def set( params )
@cookies[params.delete( :name )] = params
end
def remove( params )
@remove_cookies[params.delete( :name )] = params
end
def commit( headers )
@cookies.each_pair do |name, params|
Rack::Utils.set_cookie_header!( headers, name, params )
end
@remove_cookies.each_pair do |name, params|
Rack::Utils.delete_cookie_header!( headers, name, params )
end
end
end
The class managing the session (using Mongo as a backend):
class Database::Mongo::Session < Session
def save
expire = Time.now + @session_ttl
@framework.content.db.find_and_modify( self.collection_name, {
:query => { :name => @session_name, :id => @session_id },
:update => { :expire => expire, :name => @session_name, :id => @new_session_id || @session_id , :variables => @variables.to_hash },
:upsert => true
})
@framework.response.cookies.set(
:name => @session_name,
:value => @new_session_id || @session_id,
:path => @framework.applications.active.active_request['path'],
:domain => @framework.applications.active.active_request['host'],
:httponly => true
)
end
def delete
@framework.content.db.remove( self.collection_name, { :id => @session_id } )
@framework.response.cookies.remove( :name => @session_name )
end
end
Each time @framework.response.cookies.set
is called, it pushes a cookie data to the Framework::Response::Cookies
class @cookies
variable.
Before serving the response, a call to Framework::Response::Cookies.commit
commit the cookies using Rack::Utils
.
Sinatra clears session on post
I was suffering from the same issue as you: sessions were being cleared on post.
I have no idea why this works, but this is my solution:
#enable :sessions
use Rack::Session::Cookie, :key => 'rack.session',
:path => '/',
:secret => 'your_secret'
I literally just replaced the enable :sessions
bit with use Rack::Session::Cookie ...
and now all is good in the world.
Is there a Rack middleware for using sessions without cookies?
Rack can use custom session ID items instead of cookies:
require 'rack/session/abstract/id'
The Rack documentation may be a helpful place to start your search. I believe you're looking for the "skip" option (or "defer" option).
Docs:
ID sets up a basic framework for implementing an id based sessioning
service. Cookies sent to the client for maintaining sessions will only
contain an id reference. Only #get_session and #set_session are
required to be overwritten.
All parameters are optional.
- :key determines the name of the cookie, by default it is
'rack.session' - :path, :domain, :expire_after, :secure, and :httponly set the related
cookie options as by Rack::Response#add_cookie - :skip will not a set a cookie in the response nor update the session state
- :defer will not set a cookie in the response but still update the session
state if it is used with a backend - :renew (implementation dependent) will prompt the generation of a new
session id, and migration of data to be referenced at the new id. If
:defer is set, it will be overridden and the cookie will be set. - :sidbits sets the number of bits in length that a generated session
id will be.
These options can be set on a per request basis, at the location of
env['rack.session.options']. Additionally the id of the session can be
found within the options hash at the key :id. It is highly not
recommended to change its value.
Is Rack::Utils::Context compatible.
Not included by default; you must require 'rack/session/abstract/id' to use.
Source:
class ID
DEFAULT_OPTIONS = {
:key => 'rack.session',
:path => '/',
:domain => nil,
:expire_after => nil,
:secure => false,
:httponly => true,
:defer => false,
:renew => false,
:sidbits => 128,
:cookie_only => true,
:secure_random => (::SecureRandom rescue false)
}
I hope this gives you a lead... when you learn more, can you share your results here?
Edit:
The magic trick is to combine options :cookie_only => false
with :defer => true
. Of course, the standard Rack::Session::Cookie doesn't make much sense here, so you could do:
use Rack::Session::Pool, :cookie_only => false, :defer => true
Interestingly you can alter the options in run time. In my use case, I actually need to support a traditional cookie-based mechanism alongside the explicit parameter-passing style, so I have done the following:
class WebApp < Sinatra::Base
configure do
use Rack::Session::Pool, :key => 'session_id'
end
before do
# Switch to parameter based session management if the client is an ios device
if env['HTTP_USER_AGENT'] =~ /iOS/
session.options[:cookie_only] = false
session.options[:defer] = true
end
end
get '/' do
session[:user_id] ||= nil # This triggers a session-write, giving us a valid session-id
body "session_id=#{session.id}"
end
end
Set Rack session cookie expiration programmatically
I was trying to do the exact same thing and I figured out what the problem for me was. The session cookie gets set on every request if you have an expire_after time set. So when you say if (!remember_me), for that request the cookie's expire time gets set to nil. However, on the very next request, the session cookie is reinitialized with an expire time of 2592000. It seems the fix is to not set a default expire_after time and instead say:
# don't set default expire time
use Rack::Session::Cookie, :secret => MY_SECRET
if(remember_me)
env['rack.session.options'][:expire_after] = 2592000
end
I have unfortunately not figured out how to have a default expire_after time and to permanently extend that time programatically.
Related Topics
Error Installing Gem: Couldn't Reserve Space for Cygwin's Heap, Win32 Error 487
How to Create a Symbol from a String That Has Whitespaces
How to Create Temp Dir in Ruby
Rails: Update Model Attribute Without Invoking Callbacks
Use Separate Authentication Model with Devise on Rails
How to Sort Not Simple Hash (Hash of Hashes)
Ruby Time Object Converted from Float Doesn't Equal to Orignial Time Object
"Autotest/Rails [...] Doesn't [...] Exist. Aborting"
How to Sort a Ruby Hash Alphabetically by Keys
Regex to Match Hashtags in a Sentence Using Ruby
Consuming Non-Rest APIs in Rails with Activeresource
In a Sinatra App on Heroku, Session Is Not Shared Across Dynos
Ending a Rails 2 Url with an Ip Address Causes Routing Error
How to Enable Compression in Ruby on Rails
Rails 4 Strong Parameters Failing When Creating Instances in Rails Console