1

I have a situation where I have to construct compiled splices and feed data into them which depends on the URL variable. I struggle to solve the problem.

So there is simple file name list that needs to be rendered in a table. Simple. Files belong to a group or category so you can list all files or related to a particular category. I pull data using this function:

getFilesList :: Maybe ByteString -> AppHandler [Document]
getFilesList cat = do
  let selection = maybe [] (\c -> ["category" =: T.decodeUtf8 c]) cat
  r <- eitherWithDB $ rest =<< find (select selection "files") {project = ["blob" =: 0]}
  return $ either (const []) id r

If it gets Nothing it pulls the whole list if it gets Just category it pulls files that belongs to that category. Easy so far.

I call the above function from within a handler so that I can feed an argument into it.

listFiles :: AppHandler [Document]
listFiles = do
  cat <- getParam "cat"
  let r = maybe Nothing (\c -> if c == "all" then Nothing else Just c) cat
  render "files/list-files"
  getFilesList r

If I get "all" or Nothing on the URL - I get the full list. Anything other then that - I get a category filtered list.

The URL root looks like this

("/files/:cat",           method GET    listFiles)

But now I have a problem because the "method" function will only accept Handler App App () signature. My handler returns data to be fed into the splices.

I construct my splices like so:

listFilesS :: Splices (Splice (Handler App App))
listFilesS = "files" ## files
  where
    files = manyWithSplices runChildren file $ lift listFiles -- Feed data here
    file = do
      "file-name"     ## (pureSplice . textSplice $ at "name")
      "file-oid"      ## (pureSplice . textSplice $ id)
      "file-date"     ## (pureSplice . textSplice $ dateFromDoc)
      "file-size"     ## (pureSplice . textSplice $ fsize)
      "file-type"     ## (pureSplice . textSplice $ at "type")
      "file-auth"     ## (pureSplice . textSplice $ const "admin")
      "file-link"     ## (pureSplice . textSplice $ flink)
      "file-category" ## (pureSplice . textSplice $ at "category")
      where id = T.pack . show . valueAt "_id"
        fsize = T.pack . show . round . (flip (/) 1024) . (at "size")
        flink = T.append "/files/" . id

I cannot find a way around it. Probably just missing something stupid. Any ideas what I am doing wrong?

In any case, my handler function looks incorrect since I render the template first and then pull the data. If I fix the handler then I cant feed the data based on the URL parameter.

Confused.

r.sendecky
  • 9,933
  • 9
  • 34
  • 62

1 Answers1

1

First of all, if listFiles is just returning [Document], then you don't want to call render "files/list-files". So the first order of business is to eliminate that line entirely. You might wonder why. That brings us to the second point. Your route should look like this:

("/files/:cat", method GET $ render "files/list-files")

Your route is the result of rendering a template. That's pretty much always the case with Heist routes. Sometimes you might want to explicitly call render. Other times you might just use the routes automatically given to you by heistServe.

I can't really comment on listFilesS without seeing more of the code for the Document API, but it looks reasonable. Assuming it works properly, you just have to bind that splice for your application with something like this:

addConfig heist $ mempty { hcCompiledSplices = listFilesS }

Then just use the files tag in your "files/list-files" template.

mightybyte
  • 7,282
  • 3
  • 23
  • 39
  • Thank you. I did bind the splice, it was not the issue. The issue was that I did not realize that HTTP request is available to compiled splices. This was the hole in my understanding that led to the problem. So yes, removing the render and passing the handler to the splice is all that needed. Most of the misunderstanding is due to inverted logic and weirdness of the way compiled splices work. – r.sendecky Oct 31 '13 at 00:02
  • Yep, I remember when I first realized that the handler monad was available inside splices. That was a big epiphany! – mightybyte Oct 31 '13 at 14:30