I remain confused by a lot of this stuff.

Here is an example:

I have a site that creates pages dynamically based on information in a 
database. A good example is bio pages. Users add their bios, and then 
the bios are available through a URL.

Now if I use, for example, the user's ID in the URL, thus:

members/666

Then it is a simple matter of a lookup in the database and spit out the 
code. The page is easily bookmarked and returned to. It's even 
reasonably human readable (members/beelzebub would be even better). I 
can do some simple things to prevent scripting attacks. I've used this 
system for many years and have never had a problem.

If I use a closure instead I end up with something like this:

members/?F92019795619530=_

Can't be bookmarked. Not easily human readable. Expires. For me, this is 
essentially unworkable.

I see the benefit to continuations, but they don't seem like the best 
solution in every instance. Even in a simple CRUD app, I like being able 
to bookmark the edit page for an item and come back to it. Where I tend 
to use continuations is for deletes, or for pages I specifically want to 
expire.

So what is the best practice here, and why? How can I create my dynamic 
member pages and make them bookmarkable and non-expiring? Is there a 
Lift way that I'm missing?

Chas.

marius d. wrote:
> 
> 
> On Mar 24, 6:53 pm, Alex <[email protected]> wrote:
>> Perhaps this debate has been had before but I didn't see it.  I have a
>> feeling this might be contentious.
>>
>> Doesn't this violate the basic tenet that you should not use server
>> side state when you don't have to?
> 
> No. As long as you are binding a function we are talking about state.
> 
>>  There is no reason for instance
>> when someone is submitting a news group posting to bind an empty
>> posting in a closure and store it on the server, thereby breaking the
>> application in any number of cases:
>>
>> 1) The session times out because the user got distracted or lost their
>> connection temporarily
>> 2) The user abuses the back button
>> 3) The server fails over (assuming there is no memory replication)
>> 4) There is a temporary connection failure and the user reloads
>> 5) The server is restarted
> 
> I don't see how that would break the application. The function mapping
> is cleared is the session times out or it is terminated. Furthermore
> Lift has a garbage collection mechanism that removes the functions
> that are not utilized.
> None of the above cases breaks a Lift application ... if the
> application itself is correctly designed and implemented. If we are
> talking about clustered applications Lift currently uses sticky
> sessions mechanism meaning that all requests pertaining to a given
> session are processed by the same node. This can be easily ensured by
> load balancing rules. If a node breaks part of the conversation state
> can be ensured by application design when processed by a different
> node ...of course in the context of a different HttpSession.
> 
>> All of the above cases are recoverable with what, IMO, are properly
>> designed frameworks that minimize server-side state.  Those are the
>> things that taught us state should be stored in the client whenever
>> possible.
> 
> Yes and no. I agree with state minimization but adding burden to
> client side doesn't solve much in many cases. With Lift and Scala we
> are leveraging functions and partial functions to process requests. If
> you want that bad purely stateless handling you can also do that with
> Lift. Please see LiftRules.statelessDispatchTable.
> 
>> I saw a bit of a discussion distinguishing REST from human
>> interaction, saying human interactions are not stateless, but that
>> does not excuse the application being so vulnerable to breakage.
> 
> I still don't get where your vulnerability comes from.
> 
>> This reminds me of why I dislike many ASP applications I've used -
>> they always break when users don't behave well or when some kicks a
>> server - and users, myself included, always misbehave.  I use the back
>> button when I shouldn't, I leave forms half filled out when I answer
>> the phone, and as a frequent traveler I tend to use web applications
>> from places with shoddy internet.  I also don't like to lose my work
>> when a server fails over or is restarted.
> 
> With a bit of care for design this can be taken care. For instance if
> you have an Ajax form and the request fails, Lift will try to resend
> that ... if the retry request qoes to a new node then we are talking
> about the application design if the application has enough contextual
> information to handle that or not. Such as in forms that do not
> require logged in users (i.e. posting a comment on a blog or forum as
> anonymous) the application can safely process the form request in the
> context of a new HttpSession/LiftSession.
> 
>> There may be a few gains from designing things the lift way -
>> simplicity, security, etc - but they seem to come at too great a cost.
> 
> What is this "great cost" ... one can write poor designed applications
> in any language or framework on this Earth (dunno about other
> planets). A framework can only do so much but it does not guarantee
> flawless applications.
> 
>> There maybe some solutions to this, such as serialization of this data
>> to the client, but I'm not sure I like any of them.
> 
> That would be a performance killer.
> 
>> -Alex
>>
>> On Mar 24, 2:46 am, "marius d." <[email protected]> wrote:
>>
>>> The foo reference is captured in checkAndSave which is saved on
>>> LiftSession in function mapping.
>>> Br's,
>>> Marius
>>> On Mar 24, 10:23 am, Alex <[email protected]> wrote:
>>>> If I have this in a (not Stateful) Snippet, is the checkAndSave
>>>> closure saving state on the server?  Where is the reference to foo
>>>> saved?
>>>>   def add(form: NodeSeq) : NodeSeq = {
>>>>     val foo = Foo.create
>>>>     def checkAndSave(): Unit = foo.validate match {
>>>>       case Nil => foo.save ; S.notice("Started foo: " + foo.body)
>>>>       case xs => S.error(xs) ; S.mapSnippet("Foo.add", doBind)
>>>>     }
>>>>     def doBind(form: NodeSeq) =
>>>>       bind("foo", form,
>>>>         "body" -> foo.body.toForm,
>>>>         "submit" -> submit("Submit", checkAndSave))
>>>>     doBind(form)
>>>>   }
> > 

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to