URL Rewriting problem

107 views
Skip to first unread message

glenn

unread,
Jun 12, 2009, 1:44:55 PM6/12/09
to Lift
RewriteRequest isn't working in my app, so I must be doing something
wrong, or leaving something important out.

I have a menu in my siteMap:

Menu(Loc("contact", List("info", "contact"), "Contact Us", LocGroup
("info")))

My boot.scala contains this:

LiftRules.rewrite.append {
case RewriteRequest(
ParsePath(List("info","contact"),_,_,_),_,_) =>
RewriteResponse("content" :: Nil, Map("tag" -> "contact"))
...
}

And I have a content.html page in webapp.

Clicking on the "Contact Us" menu returns an HTTP 403 error, not
content.html.

Any help would be appreciated.

Glenn...

Derek Chen-Becker

unread,
Jun 12, 2009, 3:04:49 PM6/12/09
to lif...@googlegroups.com
Do you have a menu item that matches List("content")? If not, that's why you're getting the 403. If you use SiteMap it has to be exhaustive for all content on your site. Anything that doesn't match as SiteMap entry will get a 403 error like you got here. If you don't want to show a menu item for a particular page (probably in this case), use a Hidden Menu:

Menu(Loc("content", List("content"), "Internal Content", Hidden))

Derek

David Pollak

unread,
Jun 12, 2009, 5:39:58 PM6/12/09
to lif...@googlegroups.com
On Fri, Jun 12, 2009 at 10:44 AM, glenn <gl...@exmbly.com> wrote:

RewriteRequest isn't working in my app, so I must be doing something
wrong, or leaving something important out.

I have a menu in my siteMap:

Menu(Loc("contact", List("info", "contact"), "Contact Us", LocGroup
("info")))

My boot.scala contains this:

LiftRules.rewrite.append {
       case RewriteRequest(
               ParsePath(List("info","contact"),_,_,_),_,_) =>
                       RewriteResponse("content" :: Nil, Map("tag" -> "contact"))
      ...
}

And I have a content.html page in webapp.

I think there's a better way to achieve what you want... lemme know together some code for you.
 


Clicking on the "Contact Us" menu returns an HTTP 403 error, not
content.html.

Any help would be appreciated.

Glenn...





--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

glenn

unread,
Jun 12, 2009, 6:20:47 PM6/12/09
to Lift
David,

Here's my scenario. I've got about 30 menus organized into about 7 or
8 groups. Thanks to
help from you and Derek and others in this discussion, I can display
nested menus in
groups as a horizontal superfish menu.

Using URL Rewriting, as described in the master lift book, I created a
method:

def rewrite:LiftRules.RewritePF = {
//Services
case RewriteRequest(
ParsePath(List("services"),_,_,_),_,_) =>
RewriteResponse("content" :: Nil, Map("tag" -> "services"))
case RewriteRequest(
ParsePath(List("services","coreguard"),_,_,_),_,_) =>
RewriteResponse("content" :: Nil, Map("tag" -> "coreguard"))
case RewriteRequest(
ParsePath(List("services","estatePlanning"),_,_,_),_,_) =>
RewriteResponse("content" :: Nil, Map("tag" ->
"estatePlanning"))
case RewriteRequest( ....

...
}

That sends all my requests to a content.html template:

<lift:surround with="default" at="content">
<span><h3><lift:MySnippets.content>
<c:title/>
</lift:MySnippets.content>
</h3></span>
</lift:surround>

The snippet is just as riduculously simple:

def content(xhtml:NodeSeq):NodeSeq = {
val c = S.param("tag") openOr ""

bind("c", xhtml,
"title" -> S.?(c))
}

This navigation works, though is repititious.
It would be relatively easy to extend this idea to generate menus,
complete with navigation, programatically (say, from an xml file or a
data table) and allow
site administrators and other users to drag-and-drop menus as desired.

The point of all this, in my view, is to eventually populate
content.html with data/documents/templates/atom feeds, whatever, with
nothing
more than the RewriteResponse Map parameter, and voila, you have a
fledgling CMS built with relatively few lines of code.

If you have some alternative ideas for creating a programatic
navigation system, I would be very interested.

Glenn...


On Jun 12, 2:39 pm, David Pollak <feeder.of.the.be...@gmail.com>
wrote:
> Beginning Scalahttp://www.apress.com/book/view/1430219890

David Pollak

unread,
Jun 12, 2009, 6:32:59 PM6/12/09
to lif...@googlegroups.com
So, you want custom content with menus generated from the database... well...

class BaseContentLoc(val name: String, _aspect: String) extends Loc[CustomContent] {
  // the name of the page
  // def name = "Content"

  val BaseAspect = _aspect

  def defaultParams = Full(ContentLocStuff.NullCustomContent)

  override def forceParam = defaultParams

  // the default parameters (used for generating the menu listing)
  override def additionalKidParams = CustomContent.findAll(By(CustomContent.aspect, BaseAspect),
                                                           OrderBy(CustomContent.displayOrder, Ascending))

  // no extra parameters
  def params = List(Loc.PlaceHolder, Loc.Template(myTemplate))

  def myTemplate() =
  <lift:surround with="default-final" at="content"><lift:display /></lift:surround>


  /**
   * Generate a link based on the current page
   */
  val link =
  new Loc.Link[CustomContent](List(BaseAspect), false) {
    override def createLink(in: CustomContent) = {
      Full(Text("/"+urlEncode(BaseAspect)+"/"+urlEncode(in.page)))
    }
  }

  /**
   * What's the text of the link?
   */
  val text = new Loc.LinkText(calcLinkText _)

  def calcLinkText(in: CustomContent): NodeSeq = {
    if (in.page.length > 0) Text(in.page) else Text(name)
  }

  object Finder {
    def unapply(page: String): Option[CustomContent] =
    CustomContent.findContent(page, BaseAspect)
  }

  /**
   * Rewrite the request and emit the type-safe parameter
   */
  override val rewrite: LocRewrite =
  Full({
      case RewriteRequest(ParsePath(BaseAspect :: Finder(content) :: Nil,
                                    _, _, _), _, _) =>
        (RewriteResponse(BaseAspect :: Nil), content)
    })

  /**
   * Check for page-specific snippets and
   * do appropriate dispatching
   */
  override val snippets: SnippetTest = {
    case ("display", Full(v)) =>  display(v) _
  }

  def display(v: CustomContent)(in: NodeSeq) = v.content openOr in
}

This will autogenerate submenus based on a DB lookup of CustomeContent.

Does this help achieve your longer term goal?

Thanks,

David
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890

glenn

unread,
Jun 13, 2009, 2:45:31 PM6/13/09
to Lift
David,

Looks like I can incorporate the functionality I need just by writing
my own Loc implementation. Cool. There's a lot going on in your
code so I need to work through it, but seems like it's all there.

Thanks,

Glenn...

On Jun 12, 3:32 pm, David Pollak <feeder.of.the.be...@gmail.com>

glenn

unread,
Jun 13, 2009, 3:37:07 PM6/13/09
to Lift
David,

Just to understand your code, it looks like you are using a
CustomContent abstract class
for storing content data, or content retrieval information, in the DB.
CustomContent has at
least two fields, "aspect", and, "page", of type String, both forming
the initial request path;
a helper method, "findContent", for db retrieval; and, "content", of
type AnyRef, to hold the
actual page content.

You also have a NullCustomContent implementation, which I assume has
nulls for the aspect
and page fields.

I see how this could be extended so that the display method could
actually match against
cases, depending on the resource of the content, whether it's just
xhtml, or perhaps a Rest
URL for RSS or Atom feeds,or a PDF document, etc. The actual
discriminator could be
the specific CustomContent cases, or an enum field in the class. Do
you see something similar?

If you just concocted this in response to my post, it's darn good, or
is this something you
are already using or perhaps know of it's use in other Lift projects?
I'd be interested.

Glenn..

On Jun 12, 3:32 pm, David Pollak <feeder.of.the.be...@gmail.com>

David Pollak

unread,
Jun 13, 2009, 4:32:14 PM6/13/09
to lif...@googlegroups.com
Glenn,

On Sat, Jun 13, 2009 at 12:37 PM, glenn <gl...@exmbly.com> wrote:

David,

Just to understand your code, it looks like you are using a
CustomContent abstract class
for storing content data, or content retrieval information, in the DB.

CustomContent in my case is a Mapper class, but it need not be one... it's just something that can be located with an "aspect" and a "page" and it has a content method which returns a Box[NodeSeq].
 

CustomContent has at
least two fields, "aspect", and, "page", of type String, both forming
the initial request path;
a helper method, "findContent", for db retrieval; and, "content", of
type AnyRef, to hold the
actual page content.

You also have a NullCustomContent implementation, which I assume has
nulls for the aspect
and page fields.

Not nulls, but blanks
 


I see how this could be extended so that the display method could
actually match against
cases, depending on the resource of the content, whether it's just
xhtml, or perhaps a Rest
URL for RSS or Atom feeds,or a PDF document, etc. The actual
discriminator could be
the specific CustomContent cases, or an enum field in the class. Do
you see something similar?

At this point, once you're in SiteMap, you're in Lift's XHTML rendering pipeline, so it can only be used to render XHTML pages.  However, I've been noodling with an extension to SiteMap that will allow rendering of XML, JSON, etc. 


If you just concocted this in response to my post, it's darn good, or
is this something you
are already using or perhaps know of it's use in other Lift projects?

Varients of it are being used in production in some of my projects.

The key take-away is the additionalKidParams method which allows you to dynamically add kid menus to a given menu item.

Thanks,

David
 



--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Reply all
Reply to author
Forward
0 new messages