diff --git a/Yesod/Form/Core.hs b/Yesod/Form/Core.hs
--- a/Yesod/Form/Core.hs
+++ b/Yesod/Form/Core.hs
@@ -14,6 +14,7 @@
     , fieldsToInput
     , mapFormXml
     , checkForm
+    , checkField
     , askParams
     , askFiles
     , liftForm
@@ -190,7 +191,7 @@
             , fiName = name
             , fiInput = mkWidget theId name val False
             , fiErrors = case res of
-                            FormFailure [x] -> Just $ string x
+                            FormFailure x -> Just $ string $ unlines x
                             _ -> Nothing
             }
     return (res, [fi], UrlEncoded)
@@ -241,6 +242,10 @@
 type FormletField sub y a = Maybe a -> FormField sub y a
 type FormInput sub y = GForm sub y [GWidget sub y ()]
 
+-- | Add a validation check to a form.
+--
+-- Note that if there is a validation error, this message will /not/
+-- automatically appear on the form; for that, you need to use 'checkField'.
 checkForm :: (a -> FormResult b) -> GForm s m x a -> GForm s m x b
 checkForm f (GForm form) = GForm $ do
     (res, xml, enc) <- form
@@ -249,6 +254,32 @@
                     FormFailure e -> FormFailure e
                     FormMissing -> FormMissing
     return (res', xml, enc)
+
+-- | Add a validation check to a 'FormField'.
+--
+-- Unlike 'checkForm', the validation error will appear in the generated HTML
+-- of the form.
+checkField :: (a -> Either String b) -> FormField s m a -> FormField s m b
+checkField f (GForm form) = GForm $ do
+    (res, xml, enc) <- form
+    let (res', merr) =
+            case res of
+                FormSuccess a ->
+                    case f a of
+                        Left e -> (FormFailure [e], Just e)
+                        Right x -> (FormSuccess x, Nothing)
+                FormFailure e -> (FormFailure e, Nothing)
+                FormMissing -> (FormMissing, Nothing)
+    let xml' =
+            case merr of
+                Nothing -> xml
+                Just err -> flip map xml $ \fi -> fi
+                    { fiErrors = Just $
+                        case fiErrors fi of
+                            Nothing -> string err
+                            Just x -> x
+                    }
+    return (res', xml', enc)
 
 askParams :: Monad m => StateT Ints (ReaderT Env m) Env
 askParams = lift ask
diff --git a/Yesod/Form/Profiles.hs b/Yesod/Form/Profiles.hs
--- a/Yesod/Form/Profiles.hs
+++ b/Yesod/Form/Profiles.hs
@@ -12,7 +12,6 @@
     , emailFieldProfile
     , urlFieldProfile
     , doubleFieldProfile
-    , fileFieldProfile
     , parseDate
     , parseTime
     , Textarea (..)
@@ -20,7 +19,6 @@
 
 import Yesod.Form.Core
 import Yesod.Widget
-import Yesod.Request
 import Text.Hamlet
 import Data.Time (Day, TimeOfDay(..))
 import qualified Data.ByteString.Lazy.UTF8 as U
@@ -54,9 +52,6 @@
 %input#$theId$!name=$name$!type=number!:isReq:required!value=$val$
 |]
     }
-
-fileFieldProfile :: FieldProfile s m FileInfo
-fileFieldProfile = undefined -- FIXME
 
 dayFieldProfile :: FieldProfile sub y Day
 dayFieldProfile = FieldProfile
diff --git a/Yesod/Yesod.hs b/Yesod/Yesod.hs
--- a/Yesod/Yesod.hs
+++ b/Yesod/Yesod.hs
@@ -22,6 +22,7 @@
     , maybeAuthorized
     , widgetToPageContent
     , defaultLayoutJson
+    , redirectToPost
       -- * Defaults
     , defaultErrorHandler
       -- * Data types
@@ -418,3 +419,22 @@
 caseUtf8JoinPath = do
     "/%D7%A9%D7%9C%D7%95%D7%9D/" @=? joinPath TmpYesod "" ["שלום"] []
 #endif
+
+-- | Redirect to a POST resource.
+--
+-- This is not technically a redirect; instead, it returns an HTML page with a
+-- POST form, and some Javascript to automatically submit the form. This can be
+-- useful when you need to post a plain link somewhere that needs to cause
+-- changes on the server.
+redirectToPost :: Route master -> GHandler sub master a
+redirectToPost dest = hamletToRepHtml [$hamlet|
+!!!
+%html
+    %head
+        %title Redirecting...
+    %body!onload="document.getElementById('form').submit()"
+        %form#form!method=post!action=@dest@
+            %noscript
+                %p Javascript has been disabled; please click on the button below to be redirected.
+            %input!type=submit!value=Continue
+|] >>= sendResponse
diff --git a/yesod.cabal b/yesod.cabal
--- a/yesod.cabal
+++ b/yesod.cabal
@@ -1,5 +1,5 @@
 name:            yesod
-version:         0.5.1
+version:         0.5.2
 license:         BSD3
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
@@ -25,7 +25,7 @@
                    , time                      >= 1.1.4    && < 1.3
                    , wai                       >= 0.2.0    && < 0.3
                    , wai-extra                 >= 0.2.2    && < 0.3
-                   , authenticate              >= 0.6.3.2  && < 0.7
+                   , authenticate              >= 0.7      && < 0.8
                    , bytestring                >= 0.9.1.4  && < 0.10
                    , directory                 >= 1        && < 1.2
                    , text                      >= 0.5      && < 0.10
@@ -50,7 +50,7 @@
                    , email-validate            >= 0.2.5    && < 0.3
                    , process                   >= 1.0.1    && < 1.1
                    , web-routes                >= 0.23     && < 0.24
-                   , xss-sanitize              >= 0.1.1    && < 0.2
+                   , xss-sanitize              >= 0.2      && < 0.3
     exposed-modules: Yesod
                      Yesod.Content
                      Yesod.Dispatch
