haskellyesodyesod-forms

Yesod: Passing the current user to a form


I've looked for this, but the answer found here ends up on a list containing the value. I'm wondering if there isn't another, more straightforward way to do what I need.

I have a form:

formReview :: UserId -> Form Review
formReview uid = renderDivs $ Review <$>
              areq textField "Text" Nothing <*>
              areq intField "Rating" Nothing <*>
              areq (selectField films) "Film" Nothing <*>
              pure uid

as you can see I'm trying to pass an user ID to the form, because these are the fields for Review:

Review
    text Text
    rating Int
    film FilmId
    author UserId

it requires the ID of the author. The way I'm trying to do this is by doing the following on postReviewsR:

postReviewsR :: Handler Html
postReviewsR = do
                uid <- lookupSession "_ID"
                case uid of
                  Nothing -> do
                     defaultLayout [whamlet| <h1> User isn't logged in.|]
                  Just uid -> 
                     ((result, _), _) <- runFormPost $ formReview uid
                     case result of
                        FormSuccess review -> do
                            runDB $ insert review
                            defaultLayout [whamlet|
                                <h1> Review posted. 
                            |]
                        _ -> redirect ReviewsR

it has to be a Maybe because in theory you could try to post something without being logged in, so uid could be empty. If I try to go straight to ((result, _), _) <- runFormPost $ formReview uid it says there's a Maybe Text.

Now my problem is similar the other post, it's this error:

• Couldn't match type ‘Text’ with ‘Key User’
  Expected type: UserId
    Actual type: Text
• In the first argument of ‘formReview’, namely ‘uid’
  In the second argument of ‘($)’, namely ‘formReview uid’
  In a stmt of a 'do' block:
    ((result, _), _) <- runFormPost $ formReview uid

and the suggestion in the linked post is to use keyToValues :: Key record -> [PersistValue] to turn the Key, which apparently is just Text, into what I need, the UserId. It seems too clunky to me that I would need to do all this, then use head on that list to get the value within, all to get the ID into the form. There has to be another, more correct way, right? What am I missing here? How do I get the ID of the user who's making the Review in there?

EDIT: I should point out that I'm not using Yesod.Auth so I can't use its functions.


Solution

  • Assuming you're using a SQL backend, check out the persistent SQL documentation. You'll find the toSqlKey :: ToBackendKey SqlBackend record => Int64 -> Key record function. Basically, you'll need to parse your Text to Int64 and get a key using toSqlKey. You should probably also check if the key you're getting is actually valid.

    (You've apparently misread the error, your uid is just a Text value, but you need a UserID which is a Key User).