【问题标题】:Error when using options fields in Yesod subsite form在 Yesod 子站点表单中使用选项字段时出错
【发布时间】:2015-01-15 15:55:37
【问题描述】:

我正在尝试在子网站表单中使用 selectFieldList,但出现以下错误:

Couldn't match type 'IO' with 'HanderT master IO'

我在使用以下 sn-ps 时遇到了这个问题,其中子站点命名为 TestSub(此子站点与主站点分离):

类型:

type TestHandler a = forall master. Yesod master
    => HandlerT TestSub (HandlerT master IO) a

type Form a = forall master. Yesod master
    => Html -> MForm (HandlerT TestSub (HandlerT master IO)) (FormResult a, WidgetT TestSub IO ())

表单和处理程序:

testForm :: Form (Text, Int)
testForm = renderBootstrap3 BootstrapBasicForm $ (,)
    <$> areq textField (bfs MsgText) Nothing
    <*> areq (selectFieldList [(MsgFirst, 1), (MsgSecond, 2)]) (bfs MsgSelect) Nothing

getTestHome :: TestHandler Html
getTestHome = do
    (formWidget, _) <- generateFormPost testForm
    defaultLayoutSub $ do
        setTitleI MsgTest
        [whamlet|^{formWidget}|]

当SELECT字段替换为例如intField表单和处理程序按预期工作。在 Hoogle 上寻找 selectFieldList 时,我发现选项字段(选择、单选、复选框)与“正常”字段具有不同的签名(如下所示)。我怀疑这种差异是问题所在,但还没有找到解决方法,而不必完全实现选项字段。

选项字段签名:

selectFieldList :: (Eq a, RenderMessage site FormMessage, RenderMessage site msg)
                => [(msg, a)]
                -> Field (HandlerT site IO) a

普通字段签名:

intField :: (Monad m, Integral i, RenderMessage (HandlerSite m) FormMessage)
         => Field m i

有没有办法让选项字段在子站点上下文中工作,而无需重新实现它们?

【问题讨论】:

    标签: haskell yesod yesod-forms


    【解决方案1】:

    通常最好通过调用lift 在主站点而不是子站点中运行您的表单。您还需要稍微修改您的类型同义词以匹配,但基本思想是替换:

    (formWidget, _) <- generateFormPost testForm
    

    (formWidget, _) <- lift $ generateFormPost testForm
    

    编辑

    我仍然推荐上述方法。但是,要获得您要求的替代品,请将您的类型同义词更改为:

    type Form a =
       Html -> MForm (HandlerT HelloSub IO) (FormResult a, WidgetT HelloSub IO ())
    

    然后使用liftHandlerT:

    liftHandlerT $ generateFormPost testForm
    

    请记住,这不是子网站的设计用途,因此您可能会在继续前进时遇到更多摩擦。

    关于主翻译:您绝对可以利用它们,您只需按照RenderMessage master MessageDataType 的方式设置约束。这就是 FormMessage 到处使用的东西。

    EDIT2

    还有一个你可能会觉得有用的咒语:

    defaultLayoutSub $ liftWidgetT widget
    

    【讨论】:

    • 我一开始就是这样,但不允许我使用子站点 i18n 消息。我真的很想使用它,因为子站点是与主站点分开的包,所以我无法使用主翻译。除了消息之外,这意味着我必须添加额外的代码来呈现我想避免的所有路由 (getRouteToParent)。是否有另一种方法可以使选项字段工作而无需在主站点中运行表单?
    • 嗯,它被设计为故意以这种方式使用,以便您子站点的每个用户都可以自己覆盖翻译。也就是说,我 认为 使用 hoist liftIO 之类的东西在这里应该会有所帮助(提升机来自 mmorph)。不幸的是,我现在无法自己测试。
    • 我还没有与hoist liftIO 合作,但这可能是因为我不确定在哪里放置这些功能。除了让表单在子站点中工作之外,我看不到如何将主站点消息与单独打包的子站点一起使用。这是因为包在不知道消息的情况下不会编译,并且由于它是单独打包的,它永远无法知道 master 有哪些消息。
    • yesod-auth 包中有这方面的现有技术。看看那里。
    • MichaelSnoyman:您的意思是“yesod-auth 中的现有技术”来自Email 模块中的处理程序的表单吗?因为这些表单都没有使用AForm 或“MForm”。谢谢!
    猜你喜欢
    • 2015-08-02
    • 1970-01-01
    • 2014-04-19
    • 2016-03-08
    • 1970-01-01
    • 2015-06-30
    • 2018-01-23
    • 2014-06-04
    • 2019-05-27
    相关资源
    最近更新 更多