-->

Snap Framework: Custom snaplet handler won't r

2019-06-01 04:59发布

问题:

I'm just getting started with writing custom snaplets and hit a road block. I have the following basic snaplet which has a "roles" template located in the "snaplets/admin-pg/snaplets/heist/templates". Can someone tell me why the handleUsers function does not render the "roles" template? I get a "No handler accepted '/pgadmin/users' " error. I'm sure I'm missing something very basic. Thanks.

My main app is defined as follows. It is an instance of HasHeist

data App = App
    { _heist :: Snaplet (Heist App)
    , _pgadmin :: Snaplet (Admin App)
    }

My initializtion code for the snaplet in the main App ("Site.hs") is:

h <- nestSnaplet "" heist $ heistInit "templates"
z <- nestSnaplet "pgadmin" pgadmin $ adminPGInit h

Custom snaplet code...

data Admin b = Admin { name :: String}

adminPGInit :: HasHeist a => Snaplet (Heist a) -> SnapletInit a (Admin a)
adminPGInit h = makeSnaplet "admin-pg" description datadir $ do
  config <- getSnapletUserConfig
  fp <- getSnapletFilePath  
  addTemplatesAt h "" fp
  addRoutes [ ("/users", handleUsers) 
            , ("/foo", handleFoo)]

  return $ Admin "Admin Snaplet"
    where
      description = "PostgreSQL Admin"
      datadir = Just $ liftM (++"/resources") getDataDir



handleUsers :: HasHeist b => Handler b (Admin b) ()    
handleUsers = do
  render "roles"

handleFoo :: HasHeist b => Handler b (Admin b) () 
handleFoo = writeBS "foo from admin"

回答1:

Use addTemplates instead of addTemplatesAt. You can see from the source code that it's slightly different from what you have here.

Also, an irrelevant detail, you don't need a type parameter on the Admin data type. Since it does not use b, you don't need it as a type parameter.



回答2:

Along with changing addTemplatesAt to AddTemplates as mightybyte suggested, I also had to change the handleUsers function to:

handleUsers = do
  rURL <- getSnapletRootURL
  render $ rURL `BS.append` "/roles"

The rootURL for the custom snaplet is "pgadmin" which has to be included in the template name when calling render.