On Wed, 22 Jan 2003, Vandemoortele Simon wrote:

> This is something I would really like to discuss even though I might go
> a little of topic (sorry).

i think it's on topic.  the session management isn't that complete in it's
doccumentation and kinda tricky to understand (for me it was anyhow).

> I am entirely new to CGI scripting and trying to make an interface to edit
> my dynamic photo-album (add sections, pictures, etc). I've discovered in the
> process how inefficient it can be to code a UI with ! since every time you
> need more input from the user you have to send him to another (or the same)
> script and doing so *lose all the input you have collected*.  Until now I've
> been solving that problem by sending all the collected input along as
> 'hidden params' but that's a lot of work.  Is there a better way ? Would
> that be CGI::Session ?  or CGI::Session::PStore ?

all entirely valid/correct observations.  i think everyone deals with state
using hidden params at some point, it's just a matter of _how_much_ state you
want to deal with that way : when it's _alot_ of state that becomes pretty
tiresome.  sessions, in general, essentially deal with this by using cookies.
if you don't know this already, cookies are little peices of _textual_
information that can be stored by _your_ browser at the request of the web
server servering the page you are browsing.  the whole thing get pretty
complicated and seem to stir up debate so i'll state here that i am NO expert
on such matters - but understand enough to write usefull cgi scripts at my job
(which is with the government to take that with a grain of salt ;-) ) ...
anyhow, the way sessions work is that the 'first time' you browse a page using
them the server sends you down one little cookie - a session key - which
itself is key'd by the page you are browsing.  the next time you vist that
page your browser will send that session key to the sever _automatically_
allowing the server the know 'hey, it's you again!'.  the session key can then
be used to identify that user (his browser more like) in order to retrieve
information cached about him/her on the _server_ machine.  all the client ever
has is the cookie.  at this point i must make my disclaimer again, this is
only vaguely correct and much of the handshaking is configurable by the
browser - but i'm ignoring all of that.  so at this point the server is able
identify the client and do 'something' with that key.  one thing might be to
store information about the client in a database (there's a
cgi::session::postgresql or something like that on the raa), in a file like
cgi::session::filestore (the default session), or in a pstore (if you have my
module).  so the point is ANY session manager can do what you desire - it's
simply a matter of how difficult it will be to write.  a
cgi::session::filestore for example could not store any images directly, but
_could_ store the names/paths of them on the local filesystem.  a session
managed by postgresql could handle the images directly, but would require you
to install/learn postgresql, storing them using yaml is an option - but also
requires learning another api.  cgi::session::pstore is a little tiny thing i
wrote which is neither fast and probably has some bugs (though i've used it
extensively finding none so far) but it is _easy_ and doccumented.  if you
read the pickaxe cgi::session section and then read the pstore section you
will understand it.  here's an anotated example


  #!/usr/local/bin/ruby

  require 'cgi'
  require './cgi/session/pstore'


  # this is what the cgi will cache in it's session
  # you could make an ImageData class and perhaps
  # a Layout class or the like
  # this class is really silly, it just has a random number
  # and a Time stamp.  also, it know how to display itself
  # as html

  class SessionData
  public
    attr_accessor :time
    attr :n

    def to_html
      <<-html
	<table border=1>
	  <tr>
	    <td>n</td><td>#{n}</td>
	  </tr>
	  <tr>
	    <td>time</td><td><strong>#{time}</strong></td>
	  </tr>
	</table>
      html
    end

  private
    def initialize time = Time.now
      @time = time
      @n    = rand
    end
  end



  cgi     = CGI.new 'html3'

  session = CGI::Session.new cgi, 'database_manager' => CGI::Session::PStore

  # or
  # session =CGI::Session.new cgi,'database_manager'=>CGI::Session::FileStore
  # session =CGI::Session.new cgi,'database_manager'=>CGI::Session::MemoryStore
  # but these can only store String(key) -> String(value)!!


  # here i'm getting the client' session (if they have one) or, if this is
  # the first time the client has been here - instantiating a new one

  data = session['data']
  data = session['data'] = SessionData.new unless data


  source      = CGI.escape(ENV['DOCUMENT_ROOT'] +  ENV['SCRIPT_NAME'])
  server_addr = ENV['SERVER_ADDR']


  # simply display the session data - note that this page automatically
  # refreshes every 5 seconds (anoying!)

  $content = <<-html
    <html>
      <meta http-equiv=Refresh content=5>
      <body>
	#{data.to_html}
      </body>
    </html>
  html


  # this is _critical!  we set the time of the session data to be the
  # current time and then _update_ the session (write it to disk)

  data.time = Time.now
  session.update


  # print the page

  cgi.out { $content }


the above is simplified a little.  you can view it's output at

  http://eli.fsl.noaa.gov/ruby/class/0/cgi/session/pstore.cgi

view the original source at

  http://eli.fsl.noaa.gov/ruby/class/0/cgi/session/pstore.html


obviously it requires cgi::session::pstore which you can get from the raa.  if
you look at cgi::session::filestore and memorystore you'll understand how/why
i wrote the pstore version - it's pattern _directly_ off of those modules, i
certainly didn't make it up!  ;-)


> P.S.: Plz understand that I do have a book about ruby, access to google and
> RAA but my experience is so limited that I can't make sense of the
> information I find there. (Maybe I should find my way to more general
> information about CGI since that's the knowledge I'm lacking. Any pointers
> ?)

not really, some of the oreily perl/cgi books are informative though.  it took
me a while too, but this group was most informative.  in fact it was reading a
thread like this where matz suggested that someone complaining about no object
persistence being support via CGI::Session::MemoryStore and
CGI::Session::FileStore simply write there own CGI::Session::Pstore that
prompted me to do it.  after looking at the sources (a great source of
information if you did some sort of binary install you should get them) i
discovered that it was actually pretty simple to do!


-a

-- 

 ====================================
 | Ara Howard
 | NOAA Forecast Systems Laboratory
 | Information and Technology Services
 | Data Systems Group
 | R/FST 325 Broadway
 | Boulder, CO 80305-3328
 | Email: ahoward / fsl.noaa.gov
 | Phone:  303-497-7238
 | Fax:    303-497-7259
 ====================================