2013-05-27 10 views
6

jeśli mamy zdefiniowane 2 prostych obiektów w naszym pliku modele, na przykład: -Jak zdefiniować pole w formularzu aplikacyjnym dla klucza obcego w systemie Yesod?

Person 
    name Text 
    Age Int 
Book 
    title Text 
    author Text 

Możemy zdefiniować aplikacyjny formularz dla książki jak: -

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

Jednakże, jeśli chcemy zmienić autor już od pola tekstowego, aby identyfikator osoby, jak: -

Book 
    title Text 
    author PersonId 

Następnie powyższy formularz nie zostanie skompilowany z tego błędu: -

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' 

Jak teraz definiujemy pole autora? Czy potrzebujemy monadycznego formularza?

Dzięki!

Odpowiedz

6

Komunikat o błędzie oznacza, że ​​próbujesz użyć tekstu (z pola) jako klucza.

Można użyć checkMMap zawinąć textField i modyfikować wynik:

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) 

Funkcja findAuthor dostaje prostsze jeśli dodać unikalny konstruktora pola osobę:

Person 
    name Text 
    ... 
    UniquePerson name 

Wtedy zamiast selectFirst ... można wykonać:

mperson <- runDB $ getBy $ UniquePerson name