3.ログインFORM - S.param使ったら負け

従来通りのHTMLからのリクエストパラメータの受け取り方法。から、よりLiftをフル活用できるLiftっぽいFORMの書き方への変化を確認します。

リクエストパラメータの受け取り

■テンプレート:
<form data-lift="loginFormParam?form=post">
    ログインID:<input type="text" name="login" maxlength="24"/>
    パスワード:<input type="password" name="password" maxlength="24"/>
    <input type="submit" value="ログイン" />
</form>

■Snippet:
class LoginFormParam {
  def render = {
    if( S.post_? ){
      User.authenticate(
        S.param("login").openOr(""),
        S.param("password").openOr("")
      ) match {
        case Full(user) =>
          S.notice( "ようこそ %s さん".format(user.nickname) )
          S.redirectTo("mypage")
        case _ =>
          S.error( "ログインできません" )
      }
    }
    PassThru //何も変換しないCssSel
  }
}

S.paramでリクエストパラメータを受け取ります。Box型(Option型)なので、パラメータ名が存在しない時のデフォルト値を指定してopenします。

他は特に説明の必要もないほど簡単なコードですが、普通のウェブサイトがこんな実装で済むわけはありません。

プログラマが頭を抱える問題の一つは、FORMが複雑になればなるほど(※)このオールドスタイルでは、コードが汚れていくこと。
※行列FORM、バリデーション、Ajax、スパム除け、ユーザー状態によるFORMの切り替えなど

もう一つの問題は、デザイナーとの協業です。
デザイナーが丁寧なHTMLを作ってくれてsize/maxlengthが指定したとしても、Webデザイン時の適当な値と、要件の値とは、ほとんどの場合違うものです。
さて、これを誰が直す?どこでHTMLのリビジョン管理をしている?プログラマはHTMLなど触りたくない!などと考えているだけで頭が痛い。。


よりLiftっぽく。の第一歩

まずは、リクエストパラメータの概念を捨てましょう。Liftを使うなら、S.paramを使ったら負け!だと思っていいでしょう。


■Snippet:
class LoginFormEasy {
  
  def render = {
    var login :String = ""
    var password:String = ""
    
    def process = {
      User.authenticate( login, password ) match {
        case Full(user) =>
          S.notice( "ようこそ %s さん".format(user.nickname) )
          S.redirectTo("mypage")
        case _ =>
          S.error( "ログインできません" )
      }
    }

    "name=login" #> SHtml.onSubmit( login = _ ) &
    "name=password" #> SHtml.onSubmit( password = _ ) &
    "type=submit" #> SHtml.onSubmitUnit( process _ )
  }
}

こっちの方がコード長げえじゃないか、と突っ込み入りそうですが、複雑なケースでは明らかにコンパクトになっていくことは、使ってるうちにわかってくると思います。

体得してもらいたいのは、HTMLを全く変更せずに、サーバサイドロジックを編みこむ感じ。ここで、HTML要素の書き換えをしてやることもできます。

  "name=login" #> SHtml.text( login, login=_ , "placeholder"->"ex)taro" ) &
  "name=password" #> SHtml.password( password, password=_ , "maxlength"->"10") &
  "type=submit" #> SHtml.button( <span>Join!</span>, process _ )

SHtml.onSubmitの引数 や SHtml.textの第2引数は、(String)=>() 型の関数なので、こんなこともできます。

  "name=login" #> SHtml.onSubmit((s)=>{println(s); login=s.trim})

SHtml.onSubmitUnitの引数 や SHtml.buttonの第2引数は、() => () 型の関数です。もちろん、process関数は(よくJavaScriptでそうするみたいに)無名関数を使って書いてもいいでしょう。

  "type=submit" #> SHtml.onSubmitUnit( () => {
    println( "--- submit ! ----" )
    User.authenticate( login, password ) match {
      case Full(user) =>
        S.notice( "ようこそ %s さん".format(user.nickname) )
        S.redirectTo("mypage")
      case _ =>
        S.error( "ログインできません" )
    }
  } )

↑これは、どんな順序で各関数が実行されているかを追う以外には、特にうれしくない例ですが、要は「なんでもできる」ということがわかっていただければ。


説明が遅くなりましたが、 Liftでは、テンプレート(HTML)ファイルにロジックを埋め込むことを!!!全く!!!!許していません。

JavaのJSP、RubyのERBのようなものはそもそも記述できないので、Snippetが情報の全てです。複数のソースファイルに思考が散らかったりしないので、非常にプログラミングしやすいと思います。

HTMLマークアッパーに伝えるべきHTML作成のポイントは、

* 適切な name class id を付与してほしい。
* (言い換えれば)CSSでデザインしてほしい。

というごく当たり前の要求で済みます。

あとはごく自然に、「HTMLは触らずにサーバサイドプログラマが何とかする」というスタイルになっていくはずです。もちろんデザイン修正もガンガンやってもらって結構だ!とかまえていられるでしょう。


このシリーズ

1.Lift再入門
2.Snippetメソッドとして許される型
3.ログインFORM - S.param使ったら負け
4.サーバーサイドバリデーションとサーバサイド関数
5.行列型の編集FORM
6.Radio、Checkboxが鬼門?
7.Ajax Form
8.javascriptからsubmitできない

動作確認サンプルコード github
Simply Lift(必読)


同じカテゴリのエントリ
1.Lift再入門 / 8.javascriptからsubmitできない / 7.Ajax Form / 6.Radio、Checkboxについて / 5.行列型の編集FORM / 4.サーバーサイドバリデーションとサーバサイド関数 / 3.ログインFORM - S.param使ったら負け / 2.Snippetメソッドとして許される型 / sbt0.12.xで依存jar抽出タスク / scala2.10+lift2.5+NetBeans7.2 / Scalaで入門関数プログラミング / reactive-webを試してみました / Lift2.2M1のテンプレート機能 / Scala Compiler Plugin / View Bound/Context Bound / ScalaZa01参加してきました / Akka Frameworkチュートリアルの次 / Akka Frameworkチュートリアルその2 / Akka Frameworkチュートリアル / LiftでJCaptcha / Url Rewrite Filter / sbt-android-plugin / Android SDK for Scala / 祝Lift2.0リリース / Liftの携帯対応まとめ / Scala2.8への移行 / Lift 2.0-scala280-SNAPSHOT/sbt0.7.1 / Scalaお絵かき環境 - Kojo / Lift+Quartzでバッチ / Scala&Liftを採用した理由 / Liftでdate_select系ヘルパーを作る / LiftでAjax / LiftのSubmitかしこい / lift-mapperのpaginateを使う / snippetをspecする / Lift Mapperを拡張する / LiftのDBをMySQLに / Liftプロジェクト環境を整える / Scala本読み比べてみました / NetBeans6.7&scala / じつはScalaはライトな言語 / Scalaバザ~ル / lift1.0所感 / specsを読む / implicit def / ScalaならNetBeansがサイコー / scala勉強会@東北がスタート / それでも俺はLiftをやるってのか / Scala&Liftセットアップ / ブログリニューアル /
コメント

コメントしてください

closed.