Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a field on an applicative form for a foreign key in Yesod?

Tags:

haskell

yesod

If we have defined 2 simple objects in our models file, for example :-

Person
  name Text
  Age Int
Book
  title Text
  author Text

We can define an applicative form for Book as :-

addBookForm = renderDivs $ Book
  <$> areq textField "title" Nothing
  <*> areq textField "author" Nothing

However, if we want to change the author from just a text field, to the id of a person, as :-

Book
  title Text
  author PersonId

Then the above form won't compile, with this error :-

Couldn't match expected type `KeyBackend Database.Persist.GenericSql.Raw.SqlBackend Person' with actual type `Text'
Expected type: Field
                 sub0
                 master0
                 (KeyBackend Database.Persist.GenericSql.Raw.SqlBackend Person)
  Actual type: Field sub0 master0 Text
In the first argument of `areq', namely `textField'
In the second argument of `(<*>)', namely
  `areq textField "author" Nothing'

How do we now define the author field ? Do we need to use a monadic form ?

Thanks !

like image 282
guraaku Avatar asked May 27 '13 11:05

guraaku


1 Answers

The error message means you are trying to use Text (from the field result) as a Key.

You can use checkMMap to wrap the textField and modify the result:

addBookForm = renderDivs $ Book
  <$> areq textField "title" Nothing
  <*> (entityKey <$> areq authorField "author" Nothing)
    where
  authorField = checkMMap findAuthor (personName . entityVal) textField

  findAuthor name = do
    mperson <- runDB $ selectFirst [PersonName ==. name] []
    case mperson of
       Just person -> return $ Right person
       Nothing     -> return $ Left ("Person not found." :: Text)

The findAuthor function gets simpler if you add a unique constructor to the Person field:

Person
  name Text
  ...
  UniquePerson name

Then instead of selectFirst ... you can do

mperson <- runDB $ getBy $ UniquePerson name
like image 115
bps Avatar answered Oct 31 '22 03:10

bps