scalaのWebフレームワーク liftで遊ぶ(10) - ModelさんでCRUD画面その2
目次はこちら。
scalaのWebフレームワーク liftで遊ぶ 目次 - ゆろよろ日記
前回からの続きでCRUDする画面を作ってみるんだぜ。
Listは作ったので、残りはCreate,Update,Deleteだ。
一気に行くぞぉ。
次にCreate
じゃ、新規にレコードをCreateする画面をこんな感じで作りますよ。
src/main/webapp/user/add.html
<lift:surround with="default" at="content"> <table> <lift:snippet type="UserCrud:add" form="POST"/> </table> </lift:surround>
えー、おなじみの<lift:snippet>タグでフォームを出力するってわけです。
じゃ、前回作ったUserCrudクラスにaddメソッドを追加でっせ。
src/main/scala/com/yuroyoro/lift/crudsample/snippet/UserCrud.scala
private def saveUser(user: User) = user.validate match { case Nil => user.save; redirectTo("/user/index.html") case x => error(x); selectedUser(Full(user)) } def add(xhtml: Group): NodeSeq = selectedUser.is.openOr(new User).toForm(Empty, saveUser _) ++ <tr> <td><a href="/user/index.html">Cancel</a></td> <td><input type="submit" value="Create"/></td> </tr>
解説です。
private def saveUser(user: User) = user.validate match { case Nil => user.save; redirectTo("/user/index.html") case x => error(x); selectedUser(Full(user)) }
Create,Update共通で使用されるメソッド。パターンマッチを使って、userモデルのvalidateメソッドがNilを返す場合はuserオブジェクトをsaveでDBに保存し、index.htmlにリダイレクトしている。
Nil以外を戻すようなら、入力チェックでエラーなのでerrorメソッドでエラー処理。
def add(xhtml: Group): NodeSeq = selectedUser.is.openOr(new User).toForm(Empty, saveUser _) ++ <tr> <td><a href="/user/index.html">Cancel</a></td> <td><input type="submit" value="Create"/></td> </tr>
これはフォームを作るsnippet。selectedUser(RequestVarでリクエストをまたいで保持しているUserオブジェクト)をOpenOrで開いて(Canなので)、空だったら新しいUserオブジェクトを作成。
で、toFormメソッドでフォームとして出力するHTMLを吐き出している。
toFormはXHTMLのフォームを作り、ボタンがおされるとf: (A)=>Anyを実行。
toFormメソッドも、MetaMapperで定義されていて、デフォルトではtdタグとカラムのデータを出力するようになっている。
カスタマイズについても、同様にMapperRulesオブジェクトをいじればよし。
それでUpdate
つぎはUpdateです。
src/main/webapp/user/edit.html
<lift:surround with="default" at="content"> <table> <lift:snippet type="UserCrud:edit" form="POST"/> </table> </lift:surround>
基本的にはCreateと同じで<lift:snippet>タグでフォームを出力する仕組みですよ。
またまたUserCrudクラスにeditメソッドを追加で。
src/main/scala/com/yuroyoro/lift/crudsample/snippet/UserCrud.scala
def edit(xhtml: Group): NodeSeq = selectedUser.map(_. toForm(Empty, saveUser _) ++ <tr> <td><a href="/user/index">Cancel</a></td> <td><input type="submit" value="Save"/></td> </tr> ) openOr {error("User not found"); redirectTo("/user/index")}
解説です。
Listの画面を作るときに、各レコードの<tr>タグを出力するときに、
こんなコードを書きました。
User.findAll(OrderBy(User.id, true)).flatMap(u => <tr>{u.htmlLine} <td>{link("/user/edit", () => selectedUser(Full(u)), Text("Edit"))}</td> <td>{link("/user/delete", () => selectedUser(Full(u)), Text("Delete"))}</td> </tr>)
これは、<td>タグ内のlink("/user/edit",() => selectedUser(Full(u)), Text("Edit"))で
linkをクリックしたときには/user/editに飛ばして、第2引数の関数オブジェクトを実行するようになってます。
ここで実行される処理では、UserCrudオブジェクトのメンバ変数のselectedUserに選択されたレコードのUserオブジェクトを設定します。
で、edit()のなかで、selectedUser変数に格納されているUserオブジェクトに対して、toFormで入力項目を生成するってわけですわ。
この辺の仕組みは、addと同じで、addの場合はnew Userで新規にオブジェクトを作成しましたが、editではリンクでクリックされたUserオブジェクトに対して同様のことをやってるだけです。
出力するタグについてもMapperRulesオブジェクトの変更で対応可能。
で、toFormの第二引数には、saveUser関数オブジェクトが設定されているので、このフォームがsubmitされたときにはsaveUser関数にselectedUserオブジェクトが引数で渡されて実行、レコードをsaveで更新する流れになりますねぇ。
最後にDelete
最後は削除です。
src/main/webapp/user/delete.html
<lift:surround with="default" at="content"> <lift:snippet type="UserCrud:confirmDelete" form="POST"> Do you really want to delete <xmp:username/> <a href="/user/index">No</a> <xmp:delete/> </lift:snippet> </lift:surround>
削除画面は、消してもOK?メッセージとボタンがあります。
add,editと違ってレコードの内容をformでは出力しませんね。
で、cunfirmDeleteをUserCrudに追加します。
src/main/scala/com/yuroyoro/lift/crudsample/snippet/UserCrud.scala
def confirmDelete(xhtml: Group): NodeSeq = { (for (user <- selectedUser.is) // find the user yield { def deleteUser(ignore: String) { notice("User "+(user.firstName+" "+user.lastName)+" deleted") user.delete_! redirectTo("/user/index") } bind("xmp", xhtml, "username" --> (user.firstName.is+" "+user.lastName.is), "delete" --> submit("Delete", deleteUser)) }) openOr {error("User not found"); redirectTo("/user/index")} }
deleteConfirm内でやっていることは、yield内のブロックでdeleteUserという実際にレコードを削除する関数を定義し、bindでHTML内にuser名を出力しています。
submitで、yeald内で定義されたdeleteUser関数を渡しているので、ボタンを押してフォームが送信されると、deleteUser関数が実行されてレコードが削除されます。
noticeは、メッセージを出力する処理で、net.liftweb.http.Sで定義されています。
他にもwarningや、oepnOrでselecteduserが空だった場合のエラー処理として呼び出していたerrorなどがあります。
画面には、こんな感じで表示されますよ?
これで、liftのCRUDはおしまいです。
おもったより面倒?
なれるといろいろできるよ。
まぁソース読みましょう。