3

私はかなり長い間、別のモナドへのアクセスを必要とする消化ファンクターフォームフィールドで検証を使用する方法に頭を悩ませようとしています。短くするために私はこのような消化器の形をしています

studentRegistrationForm :: Monad m => Form Text m StudentRegistrationData
studentRegistrationForm = StudentRegistrationData
    <$> "school"    .: choice schools Nothing
    <*> "studentId" .: check studentIdErrMsg (not . T.null) (text Nothing)
    <*> "firstName" .: check firstNameErrMsg (not . T.null) (text Nothing)
    <*> "lastName"  .: check lastNameErrMsg  (not . T.null) (text Nothing)
    <*> "email"     .: check emailErrMsg (E.isValid . T.unpack) (text Nothing)

(studentIdは基本的にユーザー名です)

Snap.Snaplet.Authの機能を使用してusernameExists、入力したユーザー名が一意であるかどうかを確認します。

完全を期すために、対応するデータ型は次のとおりです。

data StudentRegistrationData = StudentRegistrationData
  { school    :: School  -- ^ school the student is enroled
  , studentId :: Text    -- ^ matriculation number of the student
  , firstName :: Text    -- ^ first name of the student
  , lastName  :: Text    -- ^ last name of the student
  , email     :: Text    -- ^ email for sending password
  } deriving (Show)

次のようなハンドラーでフォームを作成します。

studentRegistrationHandler :: AppHandler ()
studentRegistrationHandler = do
    (view, registrationData) <- runForm "form" SRF.studentRegistrationForm
    maybe (showForm "registration" view) createUser registrationData

showForm :: String -> View Text -> AppHandler ()
showForm name view =
    heistLocal (bindDigestiveSplices view) $ render template
  where
    template = BS.pack $ "student-" ++ name ++ "-form"

したがって、私が今抱えている問題は、フォーム内のAuthスナップレットの状態にアクセスする方法を理解することです。すでに合格していますか、それとも自分で合格する必要がありますか?Text.Digestive.FormcheckMの各関数validateMは、そこで役立ちますか?

消化機能とスナップ認証およびセッションの使用方法の例をいくつか見つけました。たとえば、次のようになります。

しかし、Snap.Snaplet.Authと消化機能が直接連携していることを示すものはありません。モナド変換子とリフティングに関しては、私はまだそのような初心者です...多分私にはわかりにくいかもしれません。:(

スタンドアロンの例をgithubにアップロードできます。これは、問題を説明するのに役立つ場合に問題を示しています。ヒント、ポインタ、提案は大歓迎です!:)

ハネス

アドオン:基本認証機能を示すサンプルアプリケーションを作成しました。こちらをご覧ください:digestive-functors-snap-auth-example enjoy!

4

1 に答える 1

2

すべての型がチェックされるかどうかを確認するためにこれを試したことはありませんが、一般的な考え方は次のとおりです。モナド検証を行うために checkM または validateM のいずれかを使用することは正しいです。checkM の型シグネチャは有益です。

checkM :: Monad m => v -> (a -> m Bool) -> Form v m a -> Form v m a

これは、検証関数が型 (a -> m Bool)持つ必要があり、フォーム内の型mと同じでなければならないことを示していmます。これは、フォームのタイプを次のように変更する必要があることを意味します。

studentRegistrationForm :: Form Text AppHandler StudentRegistrationData

それでは、バリデータを書きましょう。バリデーターで usernameExists 関数を使用する予定なので、その型シグネチャを確認する必要があります。

usernameExists :: Text -> Handler b (AuthManager b) Bool

(a -> m Bool)これは実際、必要な型シグネチャによく似ています。Handler b (AuthManager b)実際、はモナドなので完全一致です。しかし、(a -> m Bool)パターンと正確に一致しても、まだ完了したわけではありません。フォームを実行すると、AppHandler モナドになります。これはおそらくHandler App App、App がアプリケーションの最上位のスナップレット状態型である場所の単なる型エイリアスです。だから私たちがする必要があるのは、と統合するに変換Handler b (AuthManager b)することです。snaplet APIのwith関数はまさに私たちが必要としているものです。これにより、検証関数が非常にシンプルになります。Handler b bHandler App App

validUser :: Text -> Handler App App Bool
validUser = liftM not . with auth . usernameExists

これによりcheckM usernameErrMsg validUser、上記のコードで check を使用するのと同じように使用できます。

于 2012-05-25T20:51:29.983 に答える