8

最近我偶然发现了以下问题:
使用yesod我想

  1. 显示一个应用表单并让用户将他的数据发布到一个特殊的处理程序
  2. FormFailure 将浏览器重定向到上一页
  3. 打印错误信息...
  4. ...并重新显示已经填写了错误的用户提供的数据的表单

就我而言,这就是POST/Redirect/GET全部。

虽然第 <1-3> 点需要简单直接的实现,但我发现无法实现第 <4> 点!
yesod -form包会自动处理这个问题,但不允许在表单解析 <2> 和错误处理 <3,4> 之间进行任何重定向,就像我希望的那样。

回应迈克尔斯诺伊曼的回答

您建议我应该序列化提交的数据并在重定向后以某种方式将其注入表单。这导致了更详细的问题:

  1. 如何获取要序列化的数据?

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

  2. 如何将数据注入表单?

    如果您查看例如aopt的类型

    aopt :: Field sub master a -> FieldSettings master -> Maybe (Maybe a) -> AForm sub master (Maybe a)
    

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

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

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

4

2 回答 2

2

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

  1. 在数据库中。
  2. 在用户会话中。
  3. 作为您重定向到的 URL 的查询字符串参数的一部分。请注意,这种方法不适用于敏感数据,因为任何中间代理都会缓存表单数据。
于 2013-03-31T06:31:30.500 回答
2

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

基本上,正如迈克尔建议的那样,我们可以将数据序列化到会话中。这样做很棘手,而且把它变成一个表格更棘手。我不得不撕掉它们postEnvpostHelper因为Yesod.Form.Functions它们没有被导出,但需要这样做。

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

请注意,使用类似的东西Data.Serialize进行序列化可能会更好;但是,Show/Read实例足以满足我的需求(而且更简单)。

这是好东西。如果你想要一个完整的工作片段,你可以查看我的 gist

-- 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
于 2014-12-27T07:59:36.480 回答