scalaのWebフレームワーク liftで遊ぶ(9) - ModelさんでCRUD画面その1
目次はこちら。
scalaのWebフレームワーク liftで遊ぶ 目次 - ゆろよろ日記
ずいぶんと間が開いてしまったけど、liftネタの続きをやるよ。
前回はModelを作ったので、そいつをCRUDする画面を作ってみるんだ。
プロジェクト作成
まずはCRUD用サンプル用のプロジェクトを作成する。
mavenのコマンドでゴー。
mvn archetype:create -U -DarchetypeGroupId=net.liftweb -DarchetypeArtifactId=lift-archetype-basic -DarchetypeVersion=0.9 -DremoteRepositories=http://scala-tools.org/repo-releases -DgroupId=com.yuroyoro.lift.crudsample -DartifactId=crudsample cd crudsample mvn eclipse:eclipse
groupIdだけ変えてます。ついでにプロジェクトをEclipse用にしておく。
Eclipseにプロジェクトをインポートして準備完了だ。
Model
Modelはプロジェクトを生成したときにできるUser Modelををそのまま流用します。
まずはList
手始めに、一覧画面を作りますよ。
html作るよ。これは今まで特に変わったところはない。
src/main/webapp/index.html
<lift:surround with="default" at="content"> <a href='/add'>Add a User</a> <table width="90%"> <lift:snippet type="UserCrud:users"/> </table> </lift:surround>
4行目でUserCrud:usersっていうsnippetを呼び出している。
このsnippetの中で、Userの一覧をDBから検索するように実装しますよ。
src/main/scala/com/yuroyoro/lift/crudsample/snippet/UserCrud.scala
package com.yuroyoro.lift.crudsample.snippet import com.yuroyoro.lift.crudsample.model._ import scala.xml.{NodeSeq, Text, Group} import net.liftweb.http._ import net.liftweb.http.S import net.liftweb.mapper._ import net.liftweb.http.S._ import net.liftweb.http.SHtml._ import net.liftweb.util.Helpers._ import net.liftweb.util._ import java.util.Locale class UserCrud { private object selectedUser extends RequestVar[Can[User]](Empty) /** * Get the XHTML containing a list of users */ def users: NodeSeq = { User.find() match { case Empty => User.create.firstName("Archer").lastName("Dog").email("archer@dogfood.com").password("mypassword").save case _ => } // the header <tr>{User.htmlHeaders}<th>Edit</th><th>Delete</th></tr> :: // get and display each of the users User.findAll(OrderBy(User.id, true)).flatMap(u => <tr>{u.htmlLine} <td>{link("/simple/edit", () => selectedUser(Full(u)), Text("Edit"))}</td> <td>{link("/simple/delete", () => selectedUser(Full(u)), Text("Delete"))}</td> </tr>) } }
ここまで作って、Boot.scalaにSiteMapを追加して動かすと、こんな感じになりまっせ。
じゃあ中身の解説ですよ。
22行目:
User.find() match {
case Empty => User.create.firstName("Archer").lastName("Dog").email("archer@dogfood.com").password("mypassword").save
case _ =>
}
User Modelのfind()メソッドでusersテーブルから1件検索しています。
case Empytは検索して0件だった場合で、User.create....で1件レコードを作成。
この際に、設定するカラムをメソッドチェーン的につなげて最後にsaveを呼び出すことで、データの設定と保存を同時にやってるて寸法よ。
26行目:
// the header <tr>{User.htmlHeaders}<th>Edit</th><th>Delete</th></tr> :: // get and display each of the users User.findAll(OrderBy(User.id, true)).flatMap(u => <tr>{u.htmlLine} <td>{link("/simple/edit", () => selectedUser(Full(u)), Text("Edit"))}</td> <td>{link("/simple/delete", () => selectedUser(Full(u)), Text("Delete"))}</td> </tr>) }
ここからがsnippetの返すXmlNodeなんだけど、tableタグのヘッダー部分をUser.htmlHeadersで出力している。
このhtmlHeadersなんだけど、MetaMapperで定義されていて、デフォルトではthタグでフィールド名を出力するようになっている。
そのまんまだとth以外出せないし、日本語の名前とか出したい場合に困るので、使いづらい。
これをカスタマイズするにはMapperRulesオブジェクトをoverrideすればよい。
Google groupでも議論されていて、作者のDavid Pollakがサクッと対応してしまったのでまだ公式ドキュメントには載ってない。
Automatically generated forms
詳しいやり方は今度別なエントリで書く予定。
で、レコード本体の部分は、User.findAllで全件検索したデータ(OrderByでID順にソート)がList[Full]で返ってくるので、flatMapで1レコードづつ展開したうえでtrタグを出力している。
trタグの中身は、u.htmlLineでUserモデルの中身を出力している。
このhtmlLineも、ヘッダーと同じくMetaMapperで定義されていて、デフォルトではtdタグとカラムのデータを出力する。
カスタマイズについても、同様にMapperRulesオブジェクトをいじればオケ。
ちょっと長くなったので、今回はここまでにしておく。
次回は、Create,Update,Deleteを書きますよ。