Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
6
Help us understand the problem. What is going on with this article?
@namutaka

SkinnyFrameworkでユーザ画面と管理画面のデザインを変える方法

More than 5 years have passed since last update.

Webアプリでは1つのアプリ上にユーザ向けのエリアと管理用のエリアを持つことがよくあると思います。そのときには、ユーザ画面向けと管理画面向けでデザインやエラー画面の内容を切り替える必要があります。

SkinnyFrameworkでそのようなユーザ画面と管理画面での表示内容を出し分ける方法を紹介します。

ベースのレイアウトを切り替える

LayoutSwitchFeatureトレイトは、ビューの基板となるレイアウトファイルを切り替える機能を提供します。
このトレイトをコントローラにmixinし、defaultLayoutを設定することでレイアウトを変更できます。

LayoutSwitchFeature.scala
trait LayoutSwitchFeature extends SkinnyWebPageControllerFeatures {

  // コントローラに対するデフォルトレイアウト名(ex:"default.ssp")
  protected def defaultLayout: Option[String] = None

  /* レイアウトを設定するためにオーバーライド */
  override def render(path: String)(implicit format: Format = Format.HTML): String = {
    defaultLayout.foreach { l =>
      layout(l)
    }
    super.render(path)(format)
  }

}

エラー画面を切り替える

CustomErrorPageFilterは、haltWithBodyの呼び出しや例外発生時のエラー画面で使われるビューファイルのパスを変更します。

CustomErrorPageFilter.scala
package filter

import skinny.filter.SkinnyRenderingFilter

/**
 * エラーハンドリング用フィルタ
 */
trait CustomErrorPageFilter extends SkinnyRenderingFilter {

  protected def errorPagePath = ""

  override protected def haltWithBody[A](httpStatus: Int)(implicit format: Format = Format.HTML): A = {
    val body: String = format match {
      case Format.HTML => render(s"${errorPagePath}/error/${httpStatus}")
      case _ => renderWithFormat(Map("status" -> httpStatus, "message" -> ResponseStatus(httpStatus).message))
    }
    Option(body).map { b =>
      halt(status = httpStatus, body = b)
    }.getOrElse {
      halt(status = httpStatus)
    }
  }

  addRenderingErrorFilter {
    case e: Throwable =>
      logger.error(e.getMessage, e)
      try {
        status = 500
        render(s"${errorPagePath}/error/500")
      } catch {
        case e: Exception => throw e
      }
  }

}

コントローラの基底クラス群

上記の2機能を用意した上で、コントローラの基礎部分を以下の様に作成します。
この例は、今回の内容のみに特化したシンプルなものですので、実際には各機能ごとに色々な拡張がされると思います。

// アプリ全体のコントローラ基底trait
trait ApplicationControllerFeature extends LayoutSwitchFeature
  with AppErrorPageFilter

// ユーザ画面系のコントローラ基底trait
trait UserControllerFeature extends ApplicationControllerFeature

// 管理画面系のコントローラ基底trait
trait AdminControllerFeature extends ApplicationControllerFeature {
  override protected val errorPagePath = "/admin"
  override protected val defaultLayout = Some("admin.ssp")
}

// 管理画面用のSkinnyResource
trait AdminResource extends SkinnyResource {
  override protected def resourcesBasePath = s"/admin/${toSnakeCase(resourcesName)}"
  override protected def viewsDirectoryPath = s"/admin/${resourcesName}"
}

使い方

ここまでの準備ができてしまえば、実際のコントローラは以下の様に普通に実装して行けばよくなります。

// ユーザ画面のルートパス("/"下)に対応するコントローラ
class RootController extends SkinnyController
    with UserControllerFeature {
  def index = render("/index")
}

// 管理画面のルートパス("/admin/"下)に対応するコントローラ
class AdminRootController extends SkinnyController
    with AdminControllerFeature {
  def index = render("/admin/index")
}

ビューファイルに関しては、以下のようなファイルレイアウトになります。

src/main/webapp/WEB-INF/
+ layouts/
  - default.ssp (ユーザ画面用レイアウト)
  - admin.ssp (管理画面用レイアウト) 
+ views/
  + root/ ("/"階層に対応する。ユーザ画面用のルートページ)
  + error/ (ユーザ画面用のエラーページ)
  + admin/ ("/admin"階層に対応する。管理画面用のページ)
    + error/ (管理画面用のエラーページ)
6
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
namutaka

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
6
Help us understand the problem. What is going on with this article?