I’m new to Yesod and would like to create a custom field in which I need to do a query.
My model is the following:
Article
artname Text
title Text
body Text
parent ArticleId Maybe
UniqueArt artname
deriving Typeable
I want to create a "parent field" in which the user enters an artname
instead of a numerical id, but it will be the real id which will be stored in the database.
I cannot use checkMMap
since the invert function works outside of IO.
From what I understood of the field processing, fieldParse
takes the value entered by the user and tries to convert it to an ArticleId while fieldView
takes an ArticleId and shows a more human version.
What I’ve come up until now is the following:
parentField :: Field sub ArticleId
parentField = Field
{ fieldParse = \rawVals _ -> do
let (name:[]) = rawVals
marticle <- runDB $ getBy (UniqueArt name)
case marticle of
Nothing -> return $ (Left . SomeMessage) ("Article name invalid." :: Text)
Just article -> return $ (Right . Just) (entityKey article)
, fieldView = \idAttr nameAttr attrs eResult isReq ->
case eResult of
Right key -> do
marticle <- runDB $ get key
let name = case marticle of
Just article -> Right (articleArtname article)
Nothing -> Left ("Article key invalid." :: Text)
(fieldView textField) idAttr nameAttr attrs name isReq
Left _ -> (fieldView textField) idAttr nameAttr attrs eResult isReq
}
GHC doesn’t like the marticle <- runDB $ get key
line and gives me the following error:
Handler/Article.hs:50:21:
Couldn't match type ‘HandlerT site1 IO’
with ‘WidgetT (HandlerSite sub) IO’
Expected type: HandlerT site1 IO (Maybe Article)
-> (Maybe Article -> HandlerT site1 IO ())
-> WidgetT (HandlerSite sub) IO ()
Actual type: HandlerT site1 IO (Maybe Article)
-> (Maybe Article -> HandlerT site1 IO ()) -> HandlerT site1 IO ()
Relevant bindings include
parentField :: Field sub ArticleId
(bound at Handler/Article.hs:39:1)
In a stmt of a 'do' block: marticle <- runDB $ get key
In the expression:
do { marticle <- runDB $ get key;
let name = ...;
(fieldView textField) idAttr nameAttr attrs name isReq }
In a case alternative:
Right key
-> do { marticle <- runDB $ get key;
let name = ...;
(fieldView textField) idAttr nameAttr attrs name isReq }
Any idea ? Is it a lift
I forgot ?
In order to be able to do queries inside
fieldParse
andfieldView
, I needed some adjustments:parentField
signature must be fully specified. TheYesodPersist
andYesodPersistBackend
constraints needs to be set because of therunDB
calls.fieldView
needs to be translated to aWidget
because it is working inside a function that outputs aWidget
. That’s why thehandlerToWidget
function is used.textField
field but this imposed other constraints. Therefore I defined my ownwhamlet
.fieldEnctype
was missing.Here is the updated source code: