如何在Yesod中为外键的应用表单定义字段?

时间:2013-05-27 11:13:03

标签: haskell yesod

如果我们在模型文件中定义了2个简单对象,例如: -

Person
  name Text
  Age Int
Book
  title Text
  author Text

我们可以为Book定义一个适用表格: -

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

但是,如果我们想要将作者从文本字段更改为人员ID,则: -

Book
  title Text
  author PersonId

然后上面的表格将无法编译,出现此错误: -

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'

我们现在如何定义作者字段? 我们需要使用monadic形式吗?

谢谢!

1 个答案:

答案 0 :(得分:6)

错误消息表示您正在尝试将Text(来自字段结果)用作Key。

您可以使用checkMMap来包装textField并修改结果:

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)

如果向Person字段添加唯一构造函数,findAuthor函数会变得更简单:

Person
  name Text
  ...
  UniquePerson name

然后代替selectFirst ...你可以做

mperson <- runDB $ getBy $ UniquePerson name