博多南ウェブサービスのblog

博多南ウェブサービスのサービス紹介

【Play Framework 2.8.x のフォーム入力サンプル】都道府県のselect に入力値チェック追加(変な値をいれてPOST しても大丈夫)

Play Framework を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Play Framework 2.8.x のScala 用フォーム入力サンプルに、 都道府県を選択するメニューを追加したときのメモです。

今回は、都道府県のselect に入力値チェックを追加しました。

以下、目次

前提

変更内容

  • PalyFramework 2.8.x のドキュメント のサンプルを参考に、controllers/ にpackage 定数(Constraint[String])を定義し、
  • controllers/ の WidgetForm マッピング部分に.verifying(定義したpackage 定数) を追加
  • views/ の都道府県の表示部分に、(出力)値チェックを追加

app/controllers/WidgetFormConstraint.scala

package object controllers {

  import play.api.data.validation._

  val prefectureCheckConstraint: Constraint[String] =
    Constraint("都道府県チェック")({ value =>
      val errors = Prefecture.allPrefecture.contains(value) match {
        case false => Seq(ValidationError("error.prefecture"))
        case true  => Nil
      }
      if (errors.isEmpty) {
        Valid
      } else {
        Invalid(errors)
      }
    })
}

app/controllers/WidgetForm.scala

package controllers

object WidgetForm {
  import play.api.data.Forms._
  import play.api.data.Form

  /** A form processing DTO that maps to the form below.
    *
    * Using a class specifically for form binding reduces the chances
    * of a parameter tampering attack and makes code clearer.
    */
  case class Data(prefecture: String, price: Int)

  /** The form definition for the "create a widget" form.
    * It specifies the form fields and their types,
    * as well as how to convert from a Data to form data and vice versa.
    */

  val form = Form(
    mapping(
      "prefecture" -> nonEmptyText.verifying(prefectureCheckConstraint),
      "price" -> number(min = 0)
    )(Data.apply)(Data.unapply)
  )

}

app/views/listWidgets.scala.html

-    @for(w <- widgets) { <tr>
-       <td>@w.name</td>
+    @for(w <- widgets) { <tr>
+      <td>@{
+       if (controllers.Prefecture.allPrefecture.contains(w.prefecture)) controllers.Prefecture.allPrefecture(w.prefecture) else "none"
        }</td>

結果

都道府県のselect 入力値チェックを追加したことで、
不正な都道府県(key)のPOST 時に、「400 Bad Request」が表示された。 (ので、変な値を入れてPOST しても大丈夫かな??)

確認方法

POST のBODY の都道府県を(ブラウザの開発ツールを使って)変更

f:id:hakataminamiWS:20210222145603p:plain
POST のBODY の都道府県を(ブラウザの開発ツールを使って)変更

正常なPOST のパターン

存在するもの(GIFU)に変更 -> 200 OK

不正なPOST のパターン

存在するもの(XXX)に変更 -> 400 Bad Request

変更してみて

今回、都道府県の入力に対するバリデーションで考えた点は以下のようなこと。

  • "HOKKAIDO" -> "北海道"みたいな記述は1か所だけにしたい
  • どこに(models or controllers or views ? )記述する?

ちょっと調べると、 以下の考えに落ち着く。

  1. 一般的にどこに書くべきかは見つからない
  2. が、バリデーションは3種類との考え方はなるほど
  3. の場合、MVCのすべてに書いてもおかしくない

結果、

  • "HOKKAIDO" -> "北海道"みたいな記述はcontrollers/ に移動
  • 入力値のバリデーション -> controllers/
  • 出力値のバリデーション -> views/
  • (models で行うであろう)ビジネスロジックバリデーションは今回なし

としてみました。

Heroku 公開はこちら

Githubこちら

以上でした。