I'm working on adding a Seaside layer to one of my legacy systems (it's fun to call Rails "legacy", eh?). As I try to link back and forth from the old code to the new, I'm finding that I need my session state preserved across exits and entries. As an example, I have built a hierarchy navigation component in Seaside, and it remembers the account you selected last time you used it. So each time I call the component, the hierarchy is still open to the last account that the user selected. I'd love to use this from Rails, but each time I follow the link to /seaside/selectAccount, it starts me with a fresh session and I lose my old state. The cool remembering trick never gets to show its stuff. The solution I've come up with is hackish, which is why I'm asking for input here. Essentially, I'm subclassing WAApplication and using the Rails cookie as the session key. That way, my old session can be found when the user re-enters Seaside. This works for me, at this point. LegacyOverlay is a subclass of WAApplication:
Am I on the right track, or is there an easier way to accomplish this? Since I'm overlaying my Seaside app on an existing system, the app needs to behave as if it has multiple entry points. I just don't want it to start over every time it is entered. For my account selection component, I'm just storing the last selected account in an instance variable in the session. That means that simply locating the previous session is enough to make my component do its magic. At some point I'd rather do something less "global", like an instance variable in a component that I instantiate once and repeatedly call, but I'm not familiar enough with the internals quite yet to make it work that way. -- Ken Treis Miriam Technologies, Inc. _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
I don't know the answer, but I think it's a pretty interesting
question. It means the rest of the app is in Rails, and just this one part is in Seaside? Smalltalk's got many strengths, but it's never been regarded as a glue language that I'm aware of. I think you might be best off salting the data somewhere Seaside can get to it more easily, but I'm making a pretty wild shot in the dark, because I've never done this and I don't know what your architecture is. Is Seaside connecting to the same database Rails is? If you're using DB sessions, you can load the Rails session from the database without actually making it the Seaside session -- it's just an arbitrary set of data from which you want to extract one particular value. Does that help? On 2/18/07, Ken Treis <[hidden email]> wrote: > > I'm working on adding a Seaside layer to one of my legacy systems (it's fun > to call Rails "legacy", eh?). As I try to link back and forth from the old > code to the new, I'm finding that I need my session state preserved across > exits and entries. > > As an example, I have built a hierarchy navigation component in Seaside, and > it remembers the account you selected last time you used it. So each time I > call the component, the hierarchy is still open to the last account that the > user selected. > > I'd love to use this from Rails, but each time I follow the link to > /seaside/selectAccount, it starts me with a fresh session and I lose my old > state. The cool remembering trick never gets to show its stuff. > > The solution I've come up with is hackish, which is why I'm asking for input > here. Essentially, I'm subclassing WAApplication and using the Rails cookie > as the session key. That way, my old session can be found when the user > re-enters Seaside. > > This works for me, at this point. LegacyOverlay is a subclass of > WAApplication: > > > sessionCookieField > ^'_session_id' > > registerRequestHandler: anObject > | key | > (anObject isKindOf: Seaside.WASession) > ifFalse: [^super registerRequestHandler: anObject]. > key := Seaside.WAExternalID > fromString: (anObject currentRequest cookies at: self sessionCookieField). > self shouldCollectHandlers ifTrue: [self unregisterExpiredHandlers]. > self mutex critical: > [handlersByKey at: key put: anObject. > keysByHandler at: anObject put: key]. > ^key > > handleDefaultRequest: aRequest > | sessionKey existingSession | > sessionKey := aRequest cookies at: self sessionCookieField > ifAbsent: [^self redirectToLoginPage: aRequest]. > existingSession := handlersByKey at: (Seaside.WAExternalID fromString: > sessionKey) > ifAbsent: [^super handleDefaultRequest: aRequest]. > ^existingSession handleRequest: aRequest > > Am I on the right track, or is there an easier way to accomplish this? Since > I'm overlaying my Seaside app on an existing system, the app needs to behave > as if it has multiple entry points. I just don't want it to start over every > time it is entered. > > For my account selection component, I'm just storing the last selected > account in an instance variable in the session. That means that simply > locating the previous session is enough to make my component do its magic. > At some point I'd rather do something less "global", like an instance > variable in a component that I instantiate once and repeatedly call, but I'm > not familiar enough with the internals quite yet to make it work that way. > > > > > -- > > Ken Treis > > Miriam Technologies, Inc. > > _______________________________________________ > Seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside > > -- Giles Bowkett http://www.gilesgoatboy.org http://gilesbowkett.blogspot.com http://gilesgoatboy.blogspot.com _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Ken Treis
I realized overnight that I was making this a lot harder than it needed to be. If I just configured my Seaside app to use session cookies, I'd get the same session at every re-entry. There's no reason why the Seaside cookie needs to match the Rails cookie.
But I'd still appreciate some feedback on how to keep some state (like the last selected account in my example component below) across entries. Is a custom subclass of WASession the best place to store this? Ken On Feb 18, 2007, at 12:26 AM, Ken Treis wrote:
-- Ken Treis Miriam Technologies, Inc. _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Giles Bowkett
On Feb 18, 2007, at 7:59 AM, Giles Bowkett wrote:
> I don't know the answer, but I think it's a pretty interesting > question. It means the rest of the app is in Rails, and just this one > part is in Seaside? Yes -- that way I can build new stuff in Seaside without having to first port forward all of the old stuff. > Smalltalk's got many strengths, but it's never been regarded as a glue > language that I'm aware of. I think you might be best off salting the > data somewhere Seaside can get to it more easily, but I'm making a > pretty wild shot in the dark, because I've never done this and I don't > know what your architecture is. Is Seaside connecting to the same > database Rails is? If you're using DB sessions, you can load the Rails > session from the database without actually making it the Seaside > session -- it's just an arbitrary set of data from which you want to > extract one particular value. Does that help? That part I've actually already got figured out. Seaside and Rails talk to the same database. I'm not using DB sessions, but the file-based sessions are pretty easy to read from Smalltalk. I've used a similar trick to read PHP sessions from Rails. The cookie from the old framework tells you which file to load, and the only thing I've ever needed from the old session is the current user's ID. Login is always done in the old framework, and the new framework redirects you back to the old if you haven't logged in yet. Logout is a two-step process, where the new framework clears its session and then redirects to an old framework page that does the same. As for loading Rails sessions, I've already written a Smalltalk class that can read Ruby "Marshal" data, so it's easy to pluck the data from the Rails session. It's VisualWorks code, but it should port to Squeak pretty easily if anybody's interested. If I store persistent data in the session explicitly (by adding instance variables), then I've accomplished what I needed. But it gets ugly as the number of Seaside components grows. And it seems like a very non-Seaside way to solve the problem. "Just make a new global every time you need to store something!" That's the main issue I'd like some tips on. The other part that I haven't solved yet is how to handle multiple entry points into Seaside in a clean way. Rails will link to a particular URL for each of these, and I'd like it to work something like this: URL: /seaside/overlay/someMagicKey => rootComponent main call: (SomeComponent new...) Most of the time, these will be very coarse-grained divisions. In other words, I'd use Seaside to build a new area on the site, not just to accomplish a small task that's part of a larger Rails workflow. The account selector I mentioned is an exception to this and will require more data to be pushed back and forth, but I think I can handle all of that using URL queries. It looks like WARenderLoopMain>>start: is the place to handle custom URLs, and it also has access to the root component. Maybe that's the place to solve both of these things. I might have to play with that next. -- Ken Treis Miriam Technologies, Inc. _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Ken, I'm actually moving today, but I'm hoping to get a longer/more
useful reply off to you later this evening. In the meantime I just want to suggest -- have you looked at Pier? I know Pier provides REST support, so it could contain classes you can use to handle the URL side of the equation. By the way I'd definitely be interested to see the Marshall-reading stuff. I'm using Squeak, so I'll be able to test its portability pretty quickly. It's probably pretty straight-forward, but I'm still a bit of a n00b with Smalltalk, so it'll help me learn as well. On 2/18/07, Ken Treis <[hidden email]> wrote: > On Feb 18, 2007, at 7:59 AM, Giles Bowkett wrote: > > > I don't know the answer, but I think it's a pretty interesting > > question. It means the rest of the app is in Rails, and just this one > > part is in Seaside? > > Yes -- that way I can build new stuff in Seaside without having to > first port forward all of the old stuff. > > > Smalltalk's got many strengths, but it's never been regarded as a glue > > language that I'm aware of. I think you might be best off salting the > > data somewhere Seaside can get to it more easily, but I'm making a > > pretty wild shot in the dark, because I've never done this and I don't > > know what your architecture is. Is Seaside connecting to the same > > database Rails is? If you're using DB sessions, you can load the Rails > > session from the database without actually making it the Seaside > > session -- it's just an arbitrary set of data from which you want to > > extract one particular value. Does that help? > > That part I've actually already got figured out. > > Seaside and Rails talk to the same database. I'm not using DB > sessions, but the file-based sessions are pretty easy to read from > Smalltalk. I've used a similar trick to read PHP sessions from Rails. > The cookie from the old framework tells you which file to load, and > the only thing I've ever needed from the old session is the current > user's ID. > > Login is always done in the old framework, and the new framework > redirects you back to the old if you haven't logged in yet. Logout is > a two-step process, where the new framework clears its session and > then redirects to an old framework page that does the same. > > As for loading Rails sessions, I've already written a Smalltalk class > that can read Ruby "Marshal" data, so it's easy to pluck the data > from the Rails session. It's VisualWorks code, but it should port to > Squeak pretty easily if anybody's interested. > > If I store persistent data in the session explicitly (by adding > instance variables), then I've accomplished what I needed. But it > gets ugly as the number of Seaside components grows. And it seems > like a very non-Seaside way to solve the problem. "Just make a new > global every time you need to store something!" > > That's the main issue I'd like some tips on. The other part that I > haven't solved yet is how to handle multiple entry points into > Seaside in a clean way. Rails will link to a particular URL for each > of these, and I'd like it to work something like this: > > URL: /seaside/overlay/someMagicKey > => rootComponent main call: (SomeComponent new...) > > Most of the time, these will be very coarse-grained divisions. In > other words, I'd use Seaside to build a new area on the site, not > just to accomplish a small task that's part of a larger Rails > workflow. The account selector I mentioned is an exception to this > and will require more data to be pushed back and forth, but I think I > can handle all of that using URL queries. > > It looks like WARenderLoopMain>>start: is the place to handle custom > URLs, and it also has access to the root component. Maybe that's the > place to solve both of these things. I might have to play with that > next. > > -- > Ken Treis > Miriam Technologies, Inc. > > _______________________________________________ > Seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside > -- Giles Bowkett http://www.gilesgoatboy.org http://gilesbowkett.blogspot.com http://gilesgoatboy.blogspot.com _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
On Feb 18, 2007, at 11:19 AM, Giles Bowkett wrote:
> Ken, I'm actually moving today, but I'm hoping to get a longer/more > useful reply off to you later this evening. In the meantime I just > want to suggest -- have you looked at Pier? I know Pier provides REST > support, so it could contain classes you can use to handle the URL > side of the equation. > > By the way I'd definitely be interested to see the Marshall-reading > stuff. I'm using Squeak, so I'll be able to test its portability > pretty quickly. It's probably pretty straight-forward, but I'm still a > bit of a n00b with Smalltalk, so it'll help me learn as well. Thanks Giles, I'll finish up my unit tests for my RubyMarshal and then I'll post it here on the list. -- Ken Treis Miriam Technologies, Inc. _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by Giles Bowkett
On Feb 18, 2007, at 11:19 AM, Giles Bowkett wrote:
> By the way I'd definitely be interested to see the Marshall-reading > stuff. I'm using Squeak, so I'll be able to test its portability > pretty quickly. OK, here it is. I attached it as a VisualWorks 3.0 fileout. Let me know if this doesn't work for you, and I can try the "dangerous" squeak fileout goodie. I've been able to use this to load all of the file-serialized Rails sessions I can easily get my hands on, and it is able to handle them all. Here's the class comment from RubyMarshal: ====== RubyMarshal is an implementation of the Ruby built-in "Marshal" class. Based in part on marshal.c from the Ruby 1.8.5 codebase. Booleans, Strings, Symbols, Numbers, Arrays, and Hashes are returned as equivalent Smalltalk objects. Class names are returned as symbols. All other objects are returned as instances of RubyObject. Things that aren't supported: * The internal Ruby "DATA" type, which is used for wrapped C pointers * Options for Regexps (the flags that follow the final slash, e.g. the $i from /$foo/i. We just return regexps as their inner strings anyway (see below). Caveats: * Regexps are returned as strings that do *not* include leading and trailing slashes. * User-marshaled classes (classes that define _dump and _load or use the old marshal_dump/marshal_load protocol) are supported, but their raw dump data is the only thing we know how to load. This raw data is accessible as RubyObject>>marshalData. * Hashes with default values (defined like: "Hash.new(5)") are supported, but returned as a Dictionary. The default value is stored under the key #rubyDefault. * Floats include some information about the size of the mantissa, but we discard that and let Smalltalk handle it. This seems to work, but I make no guarantees. * Some old Modules were serialized as classes. I don't have a test for this (MODULE_OLD), but the code should work. * When particular instances have been extended (like "obj.extend (Module)"), we read the module name but throw it away. There are undoubtedly some edge cases that I missed. If you find one of these, send it to me and I'll figure out what we're missing. -- Ken Treis Miriam Technologies, Inc. _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside RubyMarshal.st (27K) Download Attachment |
Free forum by Nabble | Edit this page |