Forms 使用yesod表单发布/重定向/获取后保留不正确的用户输入

Forms 使用yesod表单发布/重定向/获取后保留不正确的用户输入,forms,haskell,yesod,post-redirect-get,Forms,Haskell,Yesod,Post Redirect Get,最近我偶然发现了以下问题: 用我想要的 显示应用程序窗体,并让用户将其数据发布到特殊处理程序 在FormFailure上,将浏览器重定向到上一页 打印错误消息 。。。并重新显示已用不正确的用户提供的数据填写的表单 就我而言,这就是一切 虽然这些要点需要一个简单而直接的实现,但我发现不可能实现这一点 yesod表单包会自动处理这个问题,但不允许像我希望的那样在表单解析和错误处理之间进行任何重定向 对迈克尔·斯诺曼回答的回应 您建议我序列化提交的数据,并在重定向后以某种方式将其注入表单。这将引出更详

最近我偶然发现了以下问题:
用我想要的

  • 显示应用程序窗体,并让用户将其数据发布到特殊处理程序
  • FormFailure
    上,将浏览器重定向到上一页
  • 打印错误消息
  • 。。。并重新显示已用不正确的用户提供的数据填写的表单
  • 就我而言,这就是一切

    虽然这些要点需要一个简单而直接的实现,但我发现不可能实现这一点
    yesod表单包会自动处理这个问题,但不允许像我希望的那样在表单解析和错误处理之间进行任何重定向

    对迈克尔·斯诺曼回答的回应 您建议我序列化提交的数据,并在重定向后以某种方式将其注入表单。这将引出更详细的问题:

  • 如何获取要序列化的数据

    我知道我可以使用
    ::GHandler s m RequestBodyContents
    ,但哪些是相关信息(字段的
    名称
    是自动生成的)

  • 如何将数据注入表单

    如果你看一看这种类型的

    您将看到,它要求默认值与
    字段
    的类型相同,因此无法重新插入可能无法正确解析的用户提供的数据

    示例:用户在
    intField
    中键入“A”。现在,我希望在重定向后能够在同一字段中显示“A”,但API不允许我这样做


  • 我应该如何处理这个问题?

    我个人认为返回带有POST请求的已填写表单是可以接受的,这正是yesod表单API优化的目的。如果您还想在表单提交失败时强制重定向,则需要序列化提交的数据并将其存储在某个位置,例如:

  • 在数据库中
  • 在用户会话中
  • 作为重定向到的URL的查询字符串参数的一部分。请注意,这种方法不适用于敏感数据,因为任何中间代理都会缓存表单数据

  • 这是一个老问题,但我今天需要这个,所以不妨将它发布给遇到相同问题的其他人

    基本上,正如Michael所建议的,我们可以将数据序列化到会话中。做这件事很棘手,而且把它做成一个表格更为棘手。我不得不从
    Yesod.Form.Functions
    中删除
    postEnv
    postHelper
    ,因为它们不是导出的,但需要这样做

    然后,可以在重定向之前在处理程序中使用
    setLastInvalidPost
    ,然后在目标处理程序中使用
    generateFormFromLastPost

    请注意,最好使用
    Data.Serialize
    之类的方法进行序列化;然而,
    Show
    /
    Read
    实例对于我的需求来说已经足够好了(而且更简单)

    这是好东西。如果需要完整的工作代码段

    --根据会话中的最后一个post数据创建表单(如果存在),否则创建空白表单。
    generateFormFromLastPost::(RenderMessage(HandlerSite m)FormMessage,MonadHandler m)=>
    (标记->MForm m(FormResult a,xml))->m(xml,Enctype)
    generateFormFromLastPost表单=do
    环境生成表单
    只是->第一个snd postHelper表单环境
    lastInvalidPostSessionKey::Text
    lastInvalidPostSessionKey=“lastInvalidPost”
    --设置从postEnv检索的post数据,忽略FileEnv。
    setLastInvalidPost::MonadHandler m=>Maybe(Env,FileEnv)->m()
    setLastInvalidPost Nothing=返回()
    setLastInvalidPost(Just(env,))=会话设置器lastInvalidPostSessionKey env
    --检索要传递给postHelper的上一个post数据。
    getLastInvalidPost::MonadHandler m=>m(可能是(Env,FileEnv))
    getLastInvalidPost=do
    一无所获
    Just env->Just(env,Map.fromList[])
    sessionSetter::(MonadHandler m,Show a)=>Text->a->m()
    sessionSetter键=设置会话键。打包。显示
    sessionGetter::(MonadHandler m,读b)=>Text->m(可能是b)
    sessionGetter键=do
    
    我会尝试用javascript和Cookie(会话-)来解决这个问题,Cookie实际上是一个好主意,但是我想避免使用javascript。我确信这个问题存在解决方案。谢谢你的回复。我会用你的方法,但它不能解决我所有的问题。我编辑了我的问题,提供了我实际需要的更详细的信息。
    aopt :: Field sub master a -> FieldSettings master -> Maybe (Maybe a) -> AForm sub master (Maybe a)
    
    -- Create a form from last post data in the session if exists, otherwise create a blank form.
    generateFormFromLastPost :: (RenderMessage (HandlerSite m) FormMessage, MonadHandler m) =>
                                (Markup -> MForm m (FormResult a, xml)) -> m (xml, Enctype)
    generateFormFromLastPost form = do
        env <- getLastInvalidPost
        case env of
            Nothing -> generateFormPost form
            Just _ -> first snd <$> postHelper form env
    
    lastInvalidPostSessionKey :: Text
    lastInvalidPostSessionKey = "lastInvalidPost"
    
    -- Sets the post data retreived from postEnv, ignoring the FileEnv.
    setLastInvalidPost :: MonadHandler m => Maybe (Env, FileEnv) -> m ()
    setLastInvalidPost Nothing = return ()
    setLastInvalidPost (Just (env, _)) = sessionSetter lastInvalidPostSessionKey env
    
    -- Retrieves the previous post data to be passed to postHelper.
    getLastInvalidPost :: MonadHandler m => m (Maybe (Env, FileEnv))
    getLastInvalidPost = do
        result <- sessionGetter lastInvalidPostSessionKey
        return $ case result of
            Nothing -> Nothing
            Just env -> Just (env, Map.fromList [])
    
    sessionSetter :: (MonadHandler m, Show a) => Text -> a -> m ()
    sessionSetter key = setSession key . pack . show
    
    sessionGetter :: (MonadHandler m, Read b) => Text -> m (Maybe b)
    sessionGetter key = do
        m <- lookupSession key
        return $ readMaybe . unpack =<< m