manual access to session data outside of request?

So, given a sessionID, I have need to read and write the session stored information 'manually', from _outside_ an actual Rails request/controller.

Readers, I know your first response may be to tell me I don't really want to do that. Trust me though, I really do, it makes sense for me in my case.

I know this wouldn't work if you're using the new cookie session storage mechanism. But if you're using a server-side session storage mechanism, I'm thinking there must be some reasonable way to do this. But I'm having trouble figuring it out.

I've tried looking through the rails source code to see how Rails reads and write session, but I'm having trouble finding the relevant code. I also figured, gee, since Rails allows pluggable session storage architecture, there must be an abstract description of what a session store must implement, and how to access it, and that might help me -- but I couldn't find that either.

Anyone have any ideas or tips? I'd like a session-storage-implementation-agnostic (assuming it's a server-side method of storage) way to read and write the session hash from outside a Rails controller.

Jonathan

So, given a sessionID, I have need to read and write the session
stored information 'manually', from _outside_ an actual Rails request/controller.

Readers, I know your first response may be to tell me I don't really want to do that. Trust me though, I really do, it makes sense for me
in my case.

I know this wouldn't work if you're using the new cookie session
storage mechanism. But if you're using a server-side session storage
mechanism, I'm thinking there must be some reasonable way to do this. But I'm having trouble figuring it out.

I've tried looking through the rails source code to see how Rails
reads and write session, but I'm having trouble finding the relevant code. I also figured, gee, since Rails allows pluggable session storage architecture, there must be an abstract description of what a session store must implement, and how to access it, and that might help me -- but I couldn't find that either.

How it is stored is almost all up to the session store - they need to
be able to fetch the data for a given session id and store some data
for a session id.

The details have changed between rails 2.2 and 2.3, in 2.2 it was the
old cgi interface, in 2.3 it's the new rack interface - you'll need to
instantiate the appropriate subclass of ActionController::SessionStore

Fred

Frederick Cheung wrote: > The details have changed between rails 2.2 and 2.3, in 2.2 it was the > old cgi interface, in 2.3 it's the new rack interface - you'll need to > instantiate the appropriate subclass of ActionController::SessionStore

This helps, thanks. Trying to look through the source and googling, I did discover that this changed very much between 2.2 and 2.3, I might need to write two versions of my code.

But since there is an abstract model for a session store, it must be possible for me to access the session store and read and write session info without knowing about the black box internals.

Once I've gotten the appropriate ActionController::SessionStore... what the heck do I do with it in order to read or write session data?

Unless the specs for how to write a session store have changed in 2.3, it may be my code doesn't need to be different for 2.3. But if it does, I can deal with that too.

They did - had to rewrite a lot of that bit of my session store for 2.3

In 2.3 Session stores have to implement a get_session method. The first argument is just the environment hash that rack gives you - you'll probably have to fiddle around a bit to workout how much you have to fake up (maybe nothing at all)

Fred

Frederick Cheung wrote:

Unless the specs for how to write a session store have changed in
2.3, it may be my code doesn't need to be different for 2.3. But if it
does, I can deal with that too.

They did - had to rewrite a lot of that bit of my session store for 2.3

Thanks Fred. It actually looks like this would be fairly
straightforward in 2.3. This blog post provides some hints:

http://devblog.michaelgalero.com/2009/02/03/guide-to-rails-metal/

But my app is not yet working with 2.3 in general, and I'd like it to work with both. And in pre-2.3, it seems, from looking at the Rails source, that it would be REALLY tricky to do this.

2.2 is a bit easier actually -

Struct.new('FakeSession', :session_id) fake_cgi_session = Struct::FakeSession.new('some session id')

session = WhateverSessionStoreClass.new(fake_cgi_session) session.restore

Fred

So now I'm thinking of another option. One would be storing this information in my own database models, keyed by Rails SessionID. But once I've done that, I've kind of duplicated the ActiveRecordStore. So another option would be writing my code to assume that the session
store is an ActiveRecordStore -- if you make this assumption, instead of trying to write store-agnostic code, then accessing the info in
pre-2.3 looks to be more do-able. And I could write code that works with
either pre 2.3 or 2.3.

If you assume ActiveRecord store it's pretty easy. find the row with
the right session id, data is right there.

Fred

Frederick Cheung wrote: > 2.2 is a bit easier actually -

I must admit that my app is still in Rails 2.1 now, for annoying reasons that will make everyone tell me I'm doing Rails wrong again.

the pre 2.2 way should work way back to rails 1.1, and possibly even further back.

Fred

Frederick Cheung wrote:

the pre 2.2 way should work way back to rails 1.1, and possibly even further back.

Huh, then I might as well do it the actual legit way, and I guess I can now easily do this in a storage-agnostic manner for both pre 2.2 and 2.2. Nice, thanks for supplying that sample code Fred, after a couple hours looking through the Rails source I wasn't any closer to figuring it out for myself.

Ah, but I guess now I have your sample code to _read_ a session. Do you have any similar magic code to write it back out to the store? I guess I can probably figure it out for myself now that I know the magic way to fake a cgi session.

Jonathan

Jonathan Rochkind wrote:

Ah, but I guess now I have your sample code to _read_ a session. Do you have any similar magic code to write it back out to the store? I guess I can probably figure it out for myself now that I know the magic way to fake a cgi session.

Ha, I've made it work! Now I just need to do it for rails 2.3 too, to have it both ways.

But here's the rails pre-2.3 version. Thanks Fred!

  Struct.new('FakeSession', :session_id)

      # Craziness to restore a session in Rails pre 2.2. Will most likely       # need to be changed for Rails 2.2.

      fake_cgi_session = Struct::FakeSession.new('some session id')

      session_obj = ActionController::Base.session_store.new(fake_cgi_session)       @session = session_obj.restore

      # Later, you've modified the hash and want to save it back to store?       # just:

      session_obj.close

You want to save something, just modify that hash, and then call

Frederick Cheung wrote:

2.2 is a bit easier actually -

Struct.new('FakeSession', :session_id) fake_cgi_session = Struct::FakeSession.new('some session id')

session = WhateverSessionStoreClass.new(fake_cgi_session) session.restore

Fred

Revisiting old history. Huh, I swear I had this working before in Rails 2.1, but I return to it to finish it off and now it does not.

on the .new(fake_cgi_session) call, I get:

NoMethodError: private method `new_session' called for #<struct Struct::FakeSession session_id="some session id">

I probably just need to get my app working in 2.3, where this is all much more consistent and rational.

Frederick Cheung wrote:

Struct.new('FakeSession', :session_id) fake_cgi_session = Struct::FakeSession.new('some session id')

session = WhateverSessionStoreClass.new(fake_cgi_session) session.restore

Okay, pre-Rails-2.2, if you want to fake a session and you want to have it work to create a new session with that ID even if one doesn't currently exist, and you sometimes use an ActiveRecord session store (phew), then instead of simply using a Struct to create a duck-typed fake session, you need something that will implement new_session too, still using the same session_id.

  class FakeSession     attr_accessor :session_id     def initialize(a_session_id)       self.session_id = a_session_id     end     def new_session       return self.session_id     end   end