前回はLiftの基本的な使い方を紹介し、簡単なウェブアルバムサービスを作りました。今回はこのウェブアルバムサービスを拡張しながら、より発展的なLiftの機能やテクニックを紹介していきます。
今回紹介することは次の通りです。
- ユーザーアカウントの扱い方
- Boxモナドを使ったテクニック
- Ajaxの実装方法
前回作ったウェブアルバムサービスではすべてのアルバムが公開されました。しかし、実際は家族や友人だけにみてほしい場合もありますよね。例えば結婚式やオフ会での写真を参加者だけで共有したり、子供の成長の記録を家族や親戚で共有できたらとても便利です。
今回は前回のウェブアルバムサービスを拡張し、いろいろな人に使ってもらえるようアカウントを導入し、アルバムごとの権限を導入し、ユーザーが設定できるようにします。
1. アカウントの導入
まずはユーザーアカウントを導入します。Liftにはユーザーアカウントを管理するためのとても便利なMetaMegaProtoUserというトレイトが用意されています。このトレイトはアカウントを保持するマッパーを作るだけでなく、アカウント管理に必要なウェブインターフェイスまでも自動で生成します。
1.1 MetaMegaProtoUserトレイトでアカウントクラスUserを作成
実際に使ってみましょう。使い方は基本的には前回アルバムや写真のマッパーを作ったLongKeyedMapperトレイトと同じです。
package jp.co.itpl.model
import net.liftweb.mapper._
import net.liftweb.common.{Box, Full, Empty, Failure}
class User extends MegaProtoUser[User] {
override def getSingleton = User
//(1) ユーザー名を表すnameというフィールドを追加
object name extends MappedString(this, 256)
}
object User extends User with MetaMegaProtoUser[User] {
//(2) アカウントに関するウェブインターフェイスの共通テンプレート
override def screenWrap = Full {
<lift:surround with="default" at="content"><lift:bind /></lift:surround>
}
//(3) 新規アカウント作成時にメールによるバリデーションを省略する
override def skipEmailValidation = true
//(4) パスワードを忘れたときの画面は不要とする
override def lostPasswordMenuLoc = Empty
//(5) アカウントを新規作成するときに必要な情報
override def signupFields = List(name, email, password)
}
MetaMegaProtoUserトレイトを継承すると姓、名、メールアドレス、国、パスワードなどのフィールドがデフォルトで用意されます。もしフィールドを追加したければ(1)のように追加できます。また、必要ないフィールドがあれば(5)のようにフィールドのリストを指定することもできます。今回はnameというフィールドを追加し、名前、メールアドレス、パスワードを使うものとします。
また、今回は簡単のためアカウント作成時のメールによるチェックやパスワードを忘れたときのための画面は省略します。(3)、(4)
1.2 ログイン済みユーザーだけがアルバムサービスを利用できるように設定
今まではユーザーアカウントというものはなく、誰でもサービスを利用できましたが、今後はログインしているユーザーだけがこのサービスを利用するようにしましょう。これはBootクラスを少し書き換えるだけで実現できます。次のようにBootクラスを書き換えてください。
...
import jp.co.itpl.model.User
...
class Boot {
def boot {
...
val entries = List(
Menu("ホーム") / "index"
//(1) ログイン時のみ見せるサイトはUser.loginFirstという認証を登録
, Menu("アルバム一覧") / "list" >> User.loginFirst
, Menu("photolist") / "photo" / "list" >> Hidden >> User.loginFirst
, Menu("アップロード") / "photo" / "upload" >> Hidden >> User.loginFirst
) ++ User.sitemap //(2) ユーザー管理のためのウェブ画面を追加
...
//(3) マッパーを定義したときはスキーマ登録する。
Schemifier.schemify(true, Log.infoF _, Album, Photo, User)
}
}
サイトマップの各ページを表すMenuクラスは >> メソッドで付加情報となるLocParam型の値を付けることができます。ここではアルバム一覧、写真一覧、アップロードの画面に対してUser.loginFirstを付け加えました。これでログインしていないユーザーからはアクセスできないようになりました。
また、ユーザー管理のためのウェブ画面のsitemapはUser.sitemapで参照できます。結合しておきましょう。(2)
前回同様、新しくマッパーを定義したときは(3)のようにスキーマ登録しておきましょう。
ここまでを保存し、ビルドして下さい。そしてローカルで起動して見ましょう。
$ mvn package
$ mvn jetty:run
ブラウザでlocalhost:8080/にアクセスしてみてください。
メニューに今まであった「アルバム一覧」という項目がなくなり、代わりに「ログイン」と「新規ユーザー作成」というメニューが追加されています(図1)。驚くべきことにそれぞれに対応するページがもうできています!あなたはユーザーマッパーを作っただけですがアカウントに関するページももうできてしまいました。
さて、早速ログインをしたいところですが、まだユーザーアカウントは一つも存在しないため、新規ユーザーを作ることにしましょう。名前、メールアドレス、パスワードを決めて新規ユーザー作成画面から作成しましょう。ここでは名前が今井宜洋、メールアドレスがy.imai@ocaml.jpとして新規ユーザーを作成します。
するとログインした状態となり、メニューには「アルバム一覧」の他に「ログアウト」「ユーザー情報の変更」「パスワードの変更」といった項目が現れます(図2)。とても簡単にユーザー認証を導入できてしまいました。