最近我偶然发现了以下问题:
使用yesod
我想
FormFailure
将浏览器重定向到上一页就我而言,这就是POST/Redirect/GET
的全部内容。
而点数< 1-3>需要一个简单而直接的实现,我发现无法实现点< 4>!
yesod-form 包自动处理此问题,但不允许在表单解析< 2>之间进行任何重定向。和错误处理< 3,4>正如我所希望的那样。
您建议我应该序列化提交的数据,并在重定向后以某种方式将其注入表单。这导致了更详细的问题:
如何获取序列化数据?
我知道我可以使用runRequestBody
:: GHandler s m RequestBodyContents
,但哪些是相关信息(字段的name
会自动生成)?
如何将数据注入表单?
如果你看一下例如aopt
aopt :: Field sub master a -> FieldSettings master -> Maybe (Maybe a) -> AForm sub master (Maybe a)
你会发现它要求默认值与Field
的类型相同,因此无法重新插入可能无法正确解析的用户提供的数据。
示例:用户在intField
中键入“A”。现在我希望能够在重定向后在同一个字段中显示“A”,但API不允许我这样做。
我该如何处理这个问题?
答案 0 :(得分:2)
我个人认为返回带有POST请求的填充表单是可以接受的,这是yesod-form API的优化。如果你想强制重定向表单提交失败,你需要序列化提交的数据并将其存储在某个地方,例如:
答案 1 :(得分:2)
老问题,但我今天需要这个,所以不妨将其发布给遇到同样问题的其他人。
基本上,正如迈克尔建议的那样,我们可以将数据序列化到会话中。这样做很棘手,加上一个表格甚至更棘手。我不得不从postEnv
翻录postHelper
和Yesod.Form.Functions
,因为它们不会被导出但是需要这样做。
然后,您可以在重定向之前在处理程序中使用setLastInvalidPost
,然后在目标处理程序中使用generateFormFromLastPost
。
请注意,使用类似Data.Serialize
的内容进行序列化可能会更好;但是,Show
/ Read
个实例足以满足我的需求(并且更简单)。
这里有好东西。如果您需要完整的工作代码段you can check out my 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