Search code examples
haskellvalidationyesod

Form validation based on values in database


I have a form where a user can update its username. A username should be unique. I thought of using the standard validation as mentioned in the Yesod book: Forms, but I don't get my head around it... Relevant database definition:

Profile
    username Text
    user UserId
    UniqueProfile user
    UniqueUsername username

Without validation, the user will receive an error-page (because of the username-uniqueness constraint on db-level). I want it to be more friendly.

How can I solve this? I was thinking that the validation should count the rows with the filled in username and should differ from the logged in UserId (a user can update other items too and keep its username). But how do I get that result to be used in the Left part of the validation?


Solution:

profileForm :: Maybe ProfileForm -> Form ProfileForm
profileForm mpf = renderBootstrap $ ProfileForm
        <$> areq usernameField (FieldSettings {fsLabel = "Username", fsTooltip = Nothing, fsId = Nothing, fsName = Nothing, fsAttrs = [("autofocus","autofocus")]}) (pfUsername <$> mpf)
    where
        unav x = do
            (Entity uid _) <- requireAuth
            usernamecount <- runDB $ count [ ProfileUsername ==. x 
                                          , ProfileUser !=. uid ]
            return $ if usernamecount > 0
                        then Left ("Username already taken" :: Text)
                        else Right x

        usernameField = checkM unav textField

Solution

  • I think you're looking for the checkM function, which will allow you to perform arbitrary actions during the validation of a field.