Ouch, it does sound ugly. Is there some alternative way to change the  
currently requested URI, for the purposes of sitemap generation and so  
on? It seems like the alternative is spinning one's own SiteMap menu  
snippet that knows to do this work?

Also, it seems odd there's no way to invoke the normal template flow  
even barring the re-init of S. The closest you can get that I know of  
is LiftSession.processSurroundAndInclude or S.render, but neither of  
those do head merge which seems to be a very key part of the rendering  
pipeline. Perhaps I'm misreading the code? It looks like  
LiftMerge.merge is called from LiftSession.processRequest which is  
called from LiftServlet.dispatchStatefulRequest, and so on, all  
private to net.liftweb.http.

At any rate, I'm just trying to help Alex, I'm not invested in any  
reason other than it's informative to try and solve. Is there any way  
to get a templated 404 response?

-Ross


On Dec 30, 2009, at 4:32 AM, Marius wrote:

> Re init-ing S is a very risky thing to do. You loose all your context
> information. uriNotFound is called by Lift from several key points.
> From those key points, Lift uses the S context and updates the
> function Map. With your example if your template is binding Scala
> functions, those function will be written to a function map that will
> not be seen by Lift as you're writing to a different S context.
>
> I would advice no doing such things or if you do, then expect side
> effects. In general avoid bypassing Lift's rendering pipeline. Lift
> does a lot of things some of them internal and missing those you can
> get into nasty hidden problems.
>
> For head merge you could use HeadHelper.scala but note that internally
> Lift doesn't use this ... it uses a more sophisticated head merge ...
> see LiftMerge.scala. HeadHelper holds the old merge. IMO it should be
> removed.
>
> I'm not really sure why you guys don't like redirects, probably to
> avoid traffic, but IMO this is not very relevant. But regardless, you
> guys have your own reasons.
>
> Br's,
> Marius
>
> On Dec 30, 9:39 am, Ross Mellgren <dri...@gmail.com> wrote:
>> I think the problem with the site map is that the request you have  
>> is for a page that doesn't exist so it can't build the current-page- 
>> relative sitemap.
>>
>> Here's a version that works:
>>
>> In Boot:
>>
>>         val notFoundNode = <lift:embed what="404" />
>>         LiftRules.uriNotFound.prepend {
>>             case _ => XhtmlTemplateResponse(notFoundNode, 404)
>>         }
>>
>> And the other part:
>>
>> object XhtmlTemplateResponse extends HeaderStuff {
>>     def apply(nodeToRender: NodeSeq, statusCode: Int): LiftResponse  
>> = {
>>         val renderedNode = {
>>             val forceToRoot: LiftRules.RewritePF = { case _ =>  
>> RewriteResponse(Req.parsePath("/"), TreeMap.empty, true) }
>>             for (req <- S.request; session <- S.session) yield
>>                 S.init(Req(req, forceToRoot::Nil), session) {
>>                     session.processSurroundAndInclude("/",  
>> nodeToRender)
>>                 }
>>         } openOr {
>>             error("No session")
>>         }
>>
>>         new XhtmlResponse(Group(renderedNode), Empty, headers,  
>> cookies, statusCode, false)
>>     }
>>
>> }
>>
>> The secret sauce is reiniting S with a new request that has been  
>> rewritten to seem as if it were a hit to /
>>
>> I'm not sure if this is a good idea, but it seems to work for the  
>> site map thing.
>>
>> However, I can't find a way to make the head merge work properly.  
>> It looks like the head merging lies in the code path inside  
>> LiftSession that is private to Lift. You could rearrange your  
>> template to make only one head I guess, or wait until someone more  
>> wise than I can direct you as far as that goes.
>>
>> -Ross
>>
>> On Dec 30, 2009, at 12:32 AM, Alex Black wrote:
>>
>>> I noticed another problem: the head merge is not working in this
>>> scenario, the resulting page is not valid XHTML because it has two
>>> head tags :)  So, this makes me think I'm going about things the  
>>> wrong
>>> way.
>>
>>> I'm hoping you can suggest the right way, to create a custom 404  
>>> page,
>>> correctly (without a redirect, with 404 status code), and  
>>> processed by
>>> the template engine so it uses our default template with sitemap  
>>> etc.
>>
>>> - Alex
>>
>>> On Dec 30, 12:22 am, Alex Black <a...@alexblack.ca> wrote:
>>>> One more detail:
>>
>>>> notFoundNode is defined like this:
>>
>>>>   val notFoundNode = <lift:embed what="404" />
>>
>>>> and 404.html like this:
>>
>>>> <lift:surround with="default" at="content">
>>>>     <head>
>>>>         <title>Page Not Found</title>
>>>>     </head>
>>>>         <h1>Page Not Found</h1>
>>>>         <p>We couldn't find the page you were looking for.</p>
>>>> </lift:surround>
>>
>>>> And my default.html hidden template has a site map tag in it, and  
>>>> the
>>>> sitemap contains a number of entries.
>>
>>>> On Dec 30, 12:14 am, Alex Black <a...@alexblack.ca> wrote:
>>
>>>>> I emailed Ross directly and said I did run with - 
>>>>> Drun.mode=production.
>>
>>>>> Here's what I'm seeing:
>>>>> 1. If I run with -Drun.mode=production, and I access a not found  
>>>>> url,
>>>>> say mysite.com/foobar, then, I *do* see the custom 404 page as
>>>>> expected, but, where I normally see my sitemap I see "No  
>>>>> Navigation
>>>>> Defined".
>>>>> 2. If I run *without* that production flag, and I access a not  
>>>>> found
>>>>> url, I get a blank white screen that says "The requested page  
>>>>> was not
>>>>> defined in your SiteMap, so access was blocked.  (This message is
>>>>> displayed in development mode only)".
>>
>>>>> So #2 is expected, #1 is not.
>>
>>>>> Ross, when you emailed me you said you tried to reproduce this,  
>>>>> but I
>>>>> think one difference between your scenario and mine is that on  
>>>>> my 404
>>>>> page I have a sitemap rendered.
>>
>>>>> So instead of what dpp had:
>>
>>>>> LiftRules.uriNotFound.prepend {
>>>>>       case _ =>  XhtmlResponse((<html> <body>Silly goose</body> </
>>>>> html>),
>>>>>                                Empty, List("Content-Type" ->  
>>>>> "text/
>>>>> html;
>>>>> charset=utf-8"), Nil, 404, S.ieMode)
>>>>>     }
>>
>>>>> I have:
>>
>>>>>     // Catch 404s
>>>>>     LiftRules.uriNotFound.prepend {
>>>>>       case (req, _) => XhtmlTemplateResponse(notFoundNode, 404)
>>>>>     }
>>
>>>>> with
>>
>>>>> object XhtmlTemplateResponse extends HeaderStuff {
>>>>>   def apply(nodeToRender: Node, statusCode: Int): LiftResponse = {
>>>>>     val renderedNode = S.render(nodeToRender,
>>>>> S.request.get.request).first
>>>>>     new XhtmlResponse(renderedNode, Empty, headers, cookies,
>>>>> statusCode, false)
>>>>>   }
>>
>>>>> }
>>
>>>>> - Alex
>>
>>>>> On Dec 29, 7:49 pm, Ross Mellgren <dri...@gmail.com> wrote:
>>
>>>>>> This is the production run mode thing dpp talked about. Try  
>>>>>> your app with -Drun.mode=production
>>
>>>>>> -Ross
>>
>>>>>> On Dec 29, 2009, at 7:39 PM, Alex Black wrote:
>>
>>>>>>> Thanks for pointing that out, the catch-all sounds dangerous.
>>
>>>>>>> I tried your suggestion, and it works well except I'm  
>>>>>>> encountering one
>>>>>>> issue, my sitemap renders as "No Navigation Defined." for urls  
>>>>>>> that
>>>>>>> are not found.   I'm using 1.1-M8, I launched jetty in  
>>>>>>> production mode
>>>>>>> as you indicated, and added the passNotFoundToChain = false.
>>
>>>>>>> Did you expect that - or is the passNotFoundToChain meant to  
>>>>>>> solve the
>>>>>>> sitemap issue?
>>
>>>>>>> - Alex
>>
>>>>>>> On Dec 29, 6:10 pm, David Pollak <feeder.of.the.be...@gmail.com>
>>>>>>> wrote:
>>>>>>>> Keep in mind that Lift's behavior for 404s differs between  
>>>>>>>> development and
>>>>>>>> production mode in Lift 1.1-xxx
>>
>>>>>>>> To have your app/Lift handle a 404 rather than passing it to  
>>>>>>>> your web
>>>>>>>> container, in Boot.scala:
>>
>>>>>>>>     LiftRules.passNotFoundToChain = false
>>
>>>>>>>>     LiftRules.uriNotFound.prepend {
>>>>>>>>       case _ =>  XhtmlResponse((<html> <body>Silly goose</ 
>>>>>>>> body> </html>),
>>>>>>>>                                Empty, List("Content-Type" ->  
>>>>>>>> "text/html;
>>>>>>>> charset=utf-8"), Nil, 404, S.ieMode)
>>>>>>>>     }
>>
>>>>>>>> In development mode, Lift will tell you about SiteMap as this  
>>>>>>>> was a common
>>>>>>>> confusion point among new developers.  In production mode,  
>>>>>>>> Lift will use
>>>>>>>> that code.  To put Lift in production mode:
>>
>>>>>>>> mvn -Drun.mode=production jetty:run
>>
>>>>>>>> I would strongly recommend against a "catch-all" entry in  
>>>>>>>> SiteMap as it will
>>>>>>>> expose every page on your site to access.
>>
>>>>>>>> On Tue, Dec 29, 2009 at 11:17 AM, Alex Black  
>>>>>>>> <a...@alexblack.ca> wrote:
>>>>>>>>> Ok, I got this working, with 1.1-M8 using S.render.
>>
>>>>>>>>>  // A node which embeds our 404 template (e.g. 404.html)
>>>>>>>>>  val notFoundNode =
>>>>>>>>>    <lift:embed what="404" />
>>
>>>>>>>>>    // Catch 404s
>>>>>>>>>    LiftRules.uriNotFound.prepend {
>>>>>>>>>      case (req, _) => XhtmlTemplateResponse(notFoundNode, 404)
>>>>>>>>>    }
>>
>>>>>>>>>  // If you're using a sitemap, make sure you have a catch- 
>>>>>>>>> all item,
>>>>>>>>> e.g
>>>>>>>>>  //    Menu(Loc("Catchall", Pair(Nil, true), "", Hidden ::  
>>>>>>>>> Nil)) ::
>>
>>>>>>>>> using this object:
>>
>>>>>>>>>  object XhtmlTemplateResponse extends HeaderStuff {
>>>>>>>>>    def apply(nodeToRender: Node, statusCode: Int):  
>>>>>>>>> LiftResponse = {
>>>>>>>>>      val renderedNode = S.render(nodeToRender,
>>>>>>>>> S.request.get.request).first
>>>>>>>>>      new XhtmlResponse(renderedNode, Empty, headers, cookies,
>>>>>>>>> statusCode, false)
>>>>>>>>>    }
>>>>>>>>>  }
>>
>>>>>>>>> I think the wiki page:
>>>>>>>>> http://wiki.liftweb.net/index.php/Setting_up_a_custom_404_page
>>>>>>>>> should be updated.  The current code hides the 404 status  
>>>>>>>>> code and
>>>>>>>>> changes the url.
>>
>>>>>>>>> I'd offer to write the new wiki page - is there a way for me  
>>>>>>>>> to get an
>>>>>>>>> account on that wiki - or is it just for contributors?
>>
>>>>>>>>> - Alex
>>
>>>>>>>>> On Dec 29, 1:20 pm, Alex Black <a...@alexblack.ca> wrote:
>>>>>>>>>>> If you want to display the contents of your 404.html,  
>>>>>>>>>>> checkout
>>>>>>>>> NodeResponse... just load up your template using the  
>>>>>>>>> template helpers (this
>>>>>>>>> will give you NodeSeq) and then you can present that back to  
>>>>>>>>> the user. Job
>>>>>>>>> done.
>>
>>>>>>>>>> I am familiar with NodeResponse and its subclasses.  I've  
>>>>>>>>>> used them in
>>>>>>>>>> our REST api.  But, what I can't figure out, is how to use  
>>>>>>>>>> them in
>>>>>>>>>> conjuction with the templating engine as you seem to be  
>>>>>>>>>> alluding to
>>>>>>>>>> (with the template helpers).
>>
>>>>>>>>>> Can you point me in the right direction? I am going to try  
>>>>>>>>>> switching
>>>>>>>>>> to M8 and then using S.render like this:
>>
>>>>>>>>>>     val node404 = <lift:surround with="default" at="content">
>>>>>>>>>>       <h1>Not Found</h1>
>>>>>>>>>>     </lift:surround>
>>
>>>>>>>>>>     LiftRules.uriNotFound.prepend {
>>>>>>>>>>       case (req, _) => XhtmlResponse(S.render(node404,  
>>>>>>>>>> req), _,
>>>>>>>>>> headers, cookies, 404, false)
>>>>>>>>>>     }
>>
>>>>>>>>>>> Cheers, Tim
>>
>>>>>>>>>>> On 29 Dec 2009, at 15:23, Alex Black wrote:
>>
>>>>>>>>>>>> But of course RewriteResponse is not a LiftResponse.   
>>>>>>>>>>>> Whats the best
>>>>>>>>>>>> way to do this?  Basically I've got a template called  
>>>>>>>>>>>> 404.html which
>>>>>>>>>>>> I'd like to display whenever there is a 404.
>>
>>>>>>>>>>>> I Just thought of something, perhaps I could add a  
>>>>>>>>>>>> RewriteRule that
>>>>>>>>>>>> matches everything?
>>
>>>>>>>>> --
>>
>>>>>>>>> You received this message because you are subscribed to the  
>>>>>>>>> Google Groups
>>>>>>>>> "Lift" group.
>>>>>>>>> To post to this group, send email to lift...@googlegroups.com.
>>>>>>>>> To unsubscribe from this group, send email to
>>>>>>>>> liftweb+unsubscr...@googlegroups.com<liftweb 
>>>>>>>>> %2bunsubscr...@googlegroups.com>
>>>>>>>>> .
>>>>>>>>> For more options, visit this group at
>>>>>>>>> http://groups.google.com/group/liftweb?hl=en.
>>
>>>>>>>> --
>>>>>>>> Lift, the simply functional web frameworkhttp://liftweb.net
>>>>>>>> Beginning Scalahttp://www.apress.com/book/view/1430219890
>>>>>>>> Follow me:http://twitter.com/dpp
>>>>>>>> Surf the harmonics
>>
>>>>>>> --
>>
>>>>>>> You received this message because you are subscribed to the  
>>>>>>> Google Groups "Lift" group.
>>>>>>> To post to this group, send email to lift...@googlegroups.com.
>>>>>>> To unsubscribe from this group, send email to 
>>>>>>> liftweb+unsubscr...@googlegroups.com 
>>>>>>> .
>>>>>>> For more options, visit this group 
>>>>>>> athttp://groups.google.com/group/liftweb?hl=en 
>>>>>>> .
>>
>>> --
>>
>>> You received this message because you are subscribed to the Google
>>
>> ...
>>
>> read more ยป
>
> --
>
> You received this message because you are subscribed to the Google  
> Groups "Lift" group.
> To post to this group, send email to lift...@googlegroups.com.
> To unsubscribe from this group, send email to 
> liftweb+unsubscr...@googlegroups.com 
> .
> For more options, visit this group at 
> http://groups.google.com/group/liftweb?hl=en 
> .
>
>

--

You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to lift...@googlegroups.com.
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.


Reply via email to