Snap-Heist: why my template is not rendered?

363 Views Asked by At

I'm trying to render a template using Snap and Heist.

I'm sure my handler function is called correctly (if I replace handler function's content with undefined, it fails as expected. Debug.Trace.trace also works as expected).

This handler function consists of one line: render "template". But for some reason I'm getting No handler accepted <url> error instead of a template not found or something like that.

I think the problem here is that I'm placing my template in wrong directory, but there's no way to know where are searched for templates. So my question is:

  1. Isn't this error message misleading? It should have been something like template not found: template.tpl
  2. Where can I know which directories are searched for templates?

I think the snap application created by snap init is the problem. I only made slight modifications on it:

  • I added one more field to App record: _myapp :: Snaplet Myapp
  • In app initializer function, I added: n <- embedSnaplet "myapp" myapp myappInit and then passed n to record.
  • I created new file src/Myapp.hs.

Here are relevant parts in Myapp.hs:

myappInit = do
    ...
    h <- nestSnaplet "" heist $ hesitInit "myapp_templates"
    addRoutes routes
    ...

routes = [ ("/submit", submitHandler) ]

submitHandler = trace "rendering submit" $ render "submit"

But for some reason even though I see rendering submit printed to console when I go to http://0.0.0.0:8000/myapp/submit, I get No handler accepted "/hsnews/submit" message as HTTP response (instead of rendered template). I have submit.tpl and _submit.tpl in snaplets/heist/myapp_templates.

2

There are 2 best solutions below

0
On

Attic's answer is very good, but didn't solve my problem. This is because of a difference between nestSnaplet and embedSnaplet.

I don't think embedSnaplet's documentation mention this difference:

Runs another snaplet's initializer and returns the initialized Snaplet value. The difference between this and nestSnaplet is the first type parameter in the third argument. The "v1 v1" makes the child snaplet think that it is top-level, which means that it will not be able to use functionality provided by snaplets included above it in the snaplet tree. This strongly isolates the child snaplet, and allows you to eliminate the b type variable. The embedded snaplet can still get functionality from other snaplets, but only if it nests or embeds the snaplet itself.

but there is also this difference, in embedSnaplet, child snaplet has a new root directory in snaplets/embeddedSnapletName and all children snaplets of the embedded snaplet will use snaplets/embeddedSnapletName folder as root.

So I had to put my templates folder to snaplets/myapp/templates and that solved it.

1
On

1.: I agree that there should be two different types of errors for rendering templates. Sadly as far as I know that isn't the case.

2.: Short answer: The directory used is written in your heistInit function. e.g.

h <- nestSnaplet "" heist $ heistInit "templates"

means that all the files in "snaplets/heist/templates/" can be accessed, including sub directories.


Long answer:

The default behaviour of the heist directory stucture works as follows: All .tpl files are accessible from the snaplet/heist/templates/ directory. Meaning

addRoutes [("template", render "template")]

will access the file

snaplets/heist/templates/template.tpl

Which can be accessed at the url

http://localhost:8000/template

You can also use sub directories, e.g.:

addRoutes [("users", render "users/index")]
path = snaplets/heist/templates/users/index.tpl
url  = http://localhost:8000/users

To modify this behaviour you can adjust the heistInit function.

Let's say you want the directory path to be "snaplets/heist/" instead of "snaplets/heist/templates/"

simply change:

h <- nestSnaplet "" heist $ heistInit "templates"

to this:

h <- nestSnaplet "" heist $ heistInit ""

The argument of heistInit is the directory location of your tpl files. So you could adjust that however you wish.

I hope this answers your question.