I can not figure out what types should go in my Foundation.hs
when implementing type classes from the authentication plugin / it's use of the auth subsite:
I can feel that I am very close, but I lack understanding. I am simply trying to use a different layout for the login/registration pages.
In Foundation.hs:
instance YesodAuthSimple App where
type AuthSimpleId App = UserId
...
-- Works
onRegisterSuccess :: YesodAuthSimple site => AuthHandler site Html
onRegisterSuccess = authLayout $ [whamlet|
$newline never
<div>
<h1>You Registered successfully.
<p>
Some text here.
|]
-- Works when I do not write a type signature
loginTemplate toParent mErr = $(widgetFile "authpartials/login")
-- Does not work with or without type signatures
customAuthLayout widget = do
master <- getYesod
mmsg <- getMessage
muser <- maybeAuthPair
mcurrentRoute <- getCurrentRoute
pc <- widgetToPageContent $ do
$(widgetFile "custom-auth-layout")
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
The 432:15 is referring to the widgetToPageContent
call.
In the type class definition Simple.hs:
class (YesodAuth site, PathPiece (AuthSimpleId site)) => YesodAuthSimple site where
type AuthSimpleId site
...
customAuthLayout :: WidgetFor site () -> AuthHandler site Html
...
I pasted in the definition of customAuthLayout
from defaultLayout
from Foundation.hs
Here is the error I get from GHC:
Foundation.hs:432:15: error:
• Could not deduce: m ~ HandlerFor App
from the context: MonadAuthHandler App m
bound by the type signature for:
customAuthLayout :: WidgetFor App () -> AuthHandler App Html
at src/Foundation.hs:(427,5)-(434,79)
‘m’ is a rigid type variable bound by
the type signature for:
customAuthLayout :: WidgetFor App () -> AuthHandler App Html
at src/Foundation.hs:(427,5)-(434,79)
Expected type: m (PageContent (Route App))
Actual type: HandlerFor App (PageContent (Route App))
• In a stmt of a 'do' block:
pc <- widgetToPageContent
$ do (do do (asWidgetT GHC.Base.. toWidget)
((blaze-markup-0.8.2.2:Text.Blaze.Internal.preEscapedText
GHC.Base.. Data.Text.pack)
"<!-- custom-auth-layout -->
<body class="d-flex align-items-center bg-auth border-top border-top-2 border-primary">")
....)
In the expression:
do master <- getYesod
mmsg <- getMessage
muser <- maybeAuthPair
mcurrentRoute <- getCurrentRoute
....
In an equation for ‘customAuthLayout’:
customAuthLayout widget
= do master <- getYesod
mmsg <- getMessage
muser <- maybeAuthPair
....
|
432 | pc <- widgetToPageContent $ do
| ^^^^^^^^^^^^^^^^^^^^^^^^...
I have used this tutorial successfully for normal (non-subsite pages) https://ersocon.net/cookbooks/yesod/html-and-seo/custom-layouts
But I am getting tripped up by the subsite types. I have read Michael Snoyman's very good old blog post on subsite types but I cannot understand GHC's error message.
I suspect either the type signature in Simple.hs is wrong, or I am missing something from the function definition.
Try to add liftHandler
before widgetToPageContent
:
...
pc <- liftHandler $ widgetToPageContent $ do
$(widgetFile "custom-auth-layout")
...
Key lines in the error message are:
Could not deduce: m ~ HandlerFor App
...
Expected type: m (PageContent (Route App))
Actual type: HandlerFor App (PageContent (Route App))
It is basically telling us that it expected a more generic type m
, but instead it got a HandlerFor App
. So the solution is simply to lift the call to widgetToPageContent
using the liftHandler
function.
To elaborate further, if we look at the type signature of the function widgetToPageContent
, we see that it returns HandlerFor site (PageContent (Route site))
. In this case, site
instantiates to App
, and that is the HandlerFor App (PageContent (Route App))
you see in the error message.
Similarly, your customLayout
function returns AuthHandler site Html
. AuthHandler
is just a type synonym that constrains site
to a type equivalent to HandlerSite m
which is also an instance of YesodAuth
. This also resolves to App
, and that is why we get MonadAuthHandler App m
and m (PageContent (Route App))
in the error message.