10

私のコントローラーアクションコードは次のようになります。

  def addIngredient() = Action { implicit request =>
    val boundForm = ingredientForm.bindFromRequest
    boundForm.fold(
      formWithErrors => BadRequest(views.html.Admin.index(formWithErrors)),
      value => {
        Async {
          val created = Service.addIngredient(value.name, value.description)
          created map { ingredient =>
            Redirect(routes.Admin.index()).flashing("success" -> "Ingredient '%s' added".format(ingredient.name))
          }

          // TODO on exception do the following
          // BadRequest(views.html.Admin.index(boundForm.copy(errors = Seq(FormError("", ex.getMessage())))))
        }
      })
  }

My Service.addIngredient(...)はPromise [Ingredient]を返しますが、カスタムValidationExceptionをスローすることもできます。この例外がスローされた場合、コメント化されたコードを返したいと思います。

現在、ページは500としてレンダリングされ、ログには次のように表示されます。

play-約束を待っていますが、エラーが発生しました:「test」という名前の材料はすでに存在します。services.ValidationException:「test」という名前の成分はすでに存在します。

2つの質問:

  • 私のサービスからこの例外を返すのは悪い考えですか?このケースを処理するためのより良い/よりスカラな方法はありますか?
  • 例外をキャッチするにはどうすればよいですか?
4

2 に答える 2

2

純粋に機能的な方法は、有効な状態とエラー状態を保持できる型を使用することだったと思います。

そのために、 Validation form scalazを使用できます

しかし、scalaz からそれ以上を必要としない場合 (そうするでしょう ^^)、Promise[Either[String, Ingredient]]結果としてa を使用foldし、Async ブロックでそのメソッドを使用する非常に単純なものを使用できます。つまりmap、プロミスが償還されたとき、および償還さfoldれたものに価値を変換することです。

良い点=>例外なし=>すべてが入力されたチェックです:-)

編集

もう少し情報が必要かもしれません.2つのオプションがあります.@kheraudに感謝します. を入れValidationませんでした。必要な場合はお問い合わせください。オブジェクトアプリケーションはコントローラーを拡張します{

  def index = Action {
    Ok(views.html.index("Your new application is ready."))
  }

  //Using Try Catch
  //  What was missing was the wrapping of the BadRequest into a Promise since the Async
  //    is requiring such result. That's done using Promise.pure
  def test1 = Async {
    try {
      val created = Promise.pure(new {val name:String = "myname"})
      created map { stuff =>
        Redirect(routes.Application.index()).flashing("success" -> "Stuff '%s' show".format(stuff.name))
      }
    } catch {
      case _ => {
        Promise.pure(Redirect(routes.Application.index()).flashing("error" -> "an error occurred man"))
      }
    }
  }


  //Using Either (kind of Validation)
  //  on the Left side => a success value with a name
  val success = Left(new {val name:String = "myname"})
  //  on the Right side the exception message (could be an Exception instance however => to keep the stack)
  val fail = Right("Bang bang!")

  // How to use that
  //   I simulate your service using Promise.pure that wraps the Either result
  //    so the return type of service should be Promise[Either[{val name:String}, String]] in this exemple
  //   Then while mapping (that is create a Promise around the convert content), we folds to create the right Result (Redirect in this case).
  // the good point => completely compiled time checked ! and no wrapping with pure for the error case.
  def test2(trySuccess:Boolean) = Async {
      val created = Promise.pure(if (trySuccess) success else fail)
      created map { stuff /* the either */ =>
        stuff.fold(
          /*success case*/s => Redirect(routes.Application.index()).flashing("success" -> "Stuff '%s' show".format(s.name)),
          /*the error case*/f => Redirect(routes.Application.index()).flashing("error" -> f)
        )

      }

  }

}
于 2012-06-06T12:31:19.907 に答える
0

Async ブロックで例外をキャッチすることはできませんか?

Async {
    try {
        val created = Service.addIngredient(value.name, value.description)
        created map { ingredient =>
            Redirect(routes.Admin.index()).flashing("success" -> "Ingredient '%s' added".format(ingredient.name))
        }
     } catch {
         case _ => {
             Promise.pure(Redirect(routes.Admin.index()).flashing("error" -> "Error while addin ingrdient"))
         }
     }
}
于 2012-06-06T11:48:11.120 に答える