Reputation: 2884
How can one interact with multiple sessions cookies (for different path or domains) in a single rack application?
For example, considering the following application using 3 locations:
Should be able to interact with 3 sessions cookies:
Rack::Session::Cookie seemed to be a good choice, but as a middleware the session cookie has to be set in config.ru and seems to be limited to one session cookie per rack application.
In this special case, the main rack application point is to easily add sub applications, so dividing the application in multiple rack application to use Rack::Session::Cookie is not a viable solution.
The ideal would be a way to interact freely with multiple session cookies from inside the rack application code.
For now, I am considering:
But both are quite tedious so I was wondering if there was a simpler way to achieve this functionality.
Thanks in advance for any advice or suggestion.
Upvotes: 4
Views: 1752
Reputation: 2884
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:
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
.
Upvotes: 3