SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Scala+Liftによる実践Webアプリケーション開発

Twitterのクローン作成で学ぶLiftによる開発の流れ

Scala+Liftによる実践Webアプリケーション開発(4)

  • X ポスト
  • このエントリーをはてなブックマークに追加

Snippetの作成

 では、Modelを利用してデータの検索や登録を行うSnippetを作成します。

 プロジェクトディレクトリ以下の 「src/main/scala/demo/twitterclone/snippet/」ディレクトリに、「Twit.scala」というファイル名で新しいファイルを作成します。

 内容は、リスト7の通りです。

[リスト7] Snippetの作成(Twit.scala)
package demo.twitterclone.snippet

import _root_.scala.xml.{NodeSeq, Text }
import _root_.net.liftweb.http.{ RequestVar, S }
import _root_.net.liftweb.http.SHtml._
import _root_.net.liftweb.util.Helpers._
import _root_.net.liftweb.util.{Box, Full}
import _root_.demo.twitterclone.model._

/**
 * ついったーのようなものの画面で使用するSnippet
 */
class Twit {
  /**
   * <lift:Twit.post>タグで呼び出されるSnippet関数
   * 入力フォームを生成する
   */
  def post( xhtml:NodeSeq  ):NodeSeq  =  {
    // User.currentUserで現在ログインしているユーザーを取得。
    val user = User.currentUser

    // Messageモデルを作成する
    val message = Message.create.user( user )

    // ユーザー名
    val name = userName( User.currentUser )

    // submitされた時点で呼び出され、メッセージの内容を
    // データベースに保存する関数
    def addMessage:Unit = message.validate match {
      // パターンマッチで、入力チェックの結果エラーが
      // 発生していない場合のみ登録
      case Nil => message.save ; S.notice("メッセージを投稿しました。")
      // エラーが発生してる場合はメッセージを表示
      case x => S.error( x )
    }

    // bind関数を利用して、引数のXHTML内で<twit:...>で始まるタグの
    // 内容を置き換える
    bind("twit", xhtml,
      "name" -> name,
      "status" -> message.status.toForm,
      "submit" -> submit( "投稿する", () => addMessage )
    )
  }

  /**
   * <lift:Twit.show>タグで呼び出されるSnippet関数
   *  投稿されたメッセージを表示する
   */
  def show( xhtml:NodeSeq  ):NodeSeq = {
    // <xml:Group>で複数のタグをグルーピング
    <xml:Group>{
      // Messageモデルから全件検索して、
      // それぞれのレコードをbind関数を利用してXHMTLに変換
      Message.findAll.flatMap{ msg =>
        bind("twit", xhtml,
          "message" -> msg.status.is ,
          "user" -> userName( msg.user.obj ),
          "dateOf" -> msg.dateOf.is.toString
        )
      }
    }</xml:Group>
  }

  /**
   * Userモデルオブジェクトからユーザー名を取得するユーティリティ関数
   */
  def userName( user:Box[User] ) = user.dmap( "Guest" ){ user =>
    user.shortName
  }
}

 このTwitクラスではpost関数とshow関数の2つのSnippetを定義しています。以下、この2つの関数について解説します。

フォームの表示とメッセージの登録を行うpost関数

 以下のリスト6は、post関数の抜粋です。どのように出力を生成しているかについて解説します。

[リスト8]post関数
  def post( xhtml:NodeSeq  ):NodeSeq  =  {
    // User.currentUserで現在ログインしているユーザーを取得。
    val user = User.currentUser  *1
    // ユーザー名
    val name = userName( User.currentUser ) *2

    // Messageモデルを作成する
    val message = Message.create.user( user ) *3

    // submitされた時点で呼び出され、メッセージの内容を
    // データベースに保存する関数
    def addMessage:Unit = message.validate match { *4
      // パターンマッチで、入力チェックの結果エラーが
      // 発生していない場合のみ登録
      case Nil => message.save ; S.notice("メッセージを投稿しました。") *5
      // エラーが発生してる場合はメッセージを表示
      case x => S.error( x ) *6
    }

    // bind関数を利用して、引数のXHTML内で<twit:...>で始まるタグの
    // 内容を置き換える
    bind("twit", xhtml, *7
      "name" -> name,
      "status" -> message.status.toForm, *8
      "submit" -> submit( "投稿する", () => addMessage ) *9
    )
  }

 このpost関数で行っている処理は、大きく分けて以下の3つです。

(1)ログインしているユーザーの取得と、Messageモデルの作成

 *1では、Liftで用意されているUserモデルを利用して、現在ログインしているユーザーを取得しています。このUserモデルから、画面に出力する名前を生成しているのが、*2の処理です。

 *3では、投稿されたメッセージに対応するMessageモデルのインスタンスを生成しています。ここでは、*1で取得したUserモデルを、Messageモデルで外部キーとして定義されているuserプロパティに設定しています。

 ここで生成されたMessageモデルですが、フォームが送信されたときに動作するaddMessage関数から参照されています。

(2)フォームから送信された際に、Messageモデルを登録するaddMessage関数の定義

 addMessage関数は、フォームが送信されたときに呼び出される関数で、Messageモデルのデータベースへの登録を行います。

 *4で、Messageモデルのvalidate関数を呼び出して、入力チェックを行います。validate関数は、エラーがある場合はList[FieldError]を返し、エラーがない場合はNilを返します。

 入力チェックの結果、エラーがない場合は、Messageモデルのsave関数を呼び出して、データベースへの登録を行います(*5)。登録後、net.liftweb.http.Sオブジェクトのnotice関数で、画面に表示するメッセージを設定しています。

 エラーがある場合は(*6)、net.liftweb.http.Sオブジェクトのerror関数に、入力チェックの結果返されたList[FieldError]オブジェクトを渡して、出力するエラーメッセージの設定をしています。

 addMessage関数は、post関数内に定義されており、post関数内の変数を参照することができます。

 *7のbind関数の処理で、addMessage関数は、クロージャとしてリクエストをまたいで利用することができるようになっていますので、*2で生成したMessageモデルも、クロージャに取り込まれてフォームが送信された時点でも利用できます。

 このように、リクエストをまたいでクロージャを利用することができるのは、LiftのFunctionMappingという機能で実現されています。詳しくは、本連載の第2回を参照してください。

(3)bind関数を用いて、フォームとして出力するXHTMLを生成する

 *7では、bind関数を用いて、post関数の引数に渡されたXHTMLに含まれる「twit」という名前空間のタグを置き換えて、フォームを生成しています。

 *8で、<twit:status/>タグに対して、message.status.toFormを設定しています。Liftのモデルの各プロパティには、toForm関数が用意されており、この関数を呼び出すことでモデルのプロパティに応じたTextFieldなどのHTMLタグを出力させることができます。

 Messageモデルのstatusプロパティは、MappedTextarea型ですので、toFormの出力は<textarea>タグになります。また、フォームが送信された際に、<textarea>タグに入力されている文字列は、自動的にMessageモデルのstatusプロパティに設定されます。

 *9は、net.liftweb.http.SHtmlオブジェクトのsubmit関数を利用して、submitボタンを生成しています。submit関数の第1引数はボタンの表示名、第2引数は「() => Any」型の関数オブジェクトです。ここで渡した関数オブジェクトが、フォームが送信された際に実行されます。ここでは、(2)で定義しているaddMessage関数を渡していますので、submitボタンでフォームが送信されるとaddMessage関数が呼び出されます。

メッセージを表示するshow関数

 リスト9は、show関数の内容です。このshow関数は、それまで投稿されたメッセージをMessageのMetaMapperオブジェクトがもつfindAll関数を呼び出して、全件を取得しています。

 取得した結果は、List[Message]型なので、flatMap関数でMessageモデルのインスタンスが持つデータを、bind関数でXHTMLに変換しています。

[リスト9]show関数
  def show( xhtml:NodeSeq  ):NodeSeq = {
    // <xml:Group>で複数のタグをグルーピング
    <xml:Group>{
      // Messageモデルから全件検索して、
      // それぞれのレコードをbind関数を利用してXHMTLに変換
      Message.findAll.flatMap{ msg =>
        bind("twit", xhtml,
          "message" -> msg.status.is ,
          "user" -> userName( msg.user.obj ),
          "dateOf" -> msg.dateOf.is.toString
        )
      }
    }</xml:Group>
  }

次のページ
設定ファイルを修正する

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Scala+Liftによる実践Webアプリケーション開発連載記事一覧

もっと読む

この記事の著者

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

WINGSプロジェクト 尾崎 智仁(オザキ トモヒト)

WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/4772 2010/02/08 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング