[Yesod入門(8)] DB操作3, データ修正

[Yesod入門(8)] DB操作3, データ修正

Handlerの編集(リソースの追加)

今回はデータを修正をできるようにしてみます。Handlerを新しく作ってもよいのですが、面倒なので Article.hs に修正用のリソースを追加で定義してやります。

ASP.NET MVC だとコントローラの中のメソッドでCRUDのメソッドを全部まとめて実装したりするのを見るのでこのようにしてみました。

config/routes

/Article/#ArticleId ArticleUpdateR GET POST

これを追加することで、ArticleId(エンティティのキー)を受け取る事ができる routes を定義できました。機能の実装です。

Handler/Article.hs

module Handler.Article where

import Import

-- フォーム取得
articleForm :: Maybe Article -> Html -> MForm Handler (FormResult Article, Widget)
articleForm article extra = do
	(titleResult, titleView)            <- mreq textField "タイトル" (articleTitle <$> article)
	(publishedResult, publishedView)    <- mreq dayField "公開日" (articlePublished <$> article)
	(viewCountResult, viewCountView)    <- mopt intField "ビュー数" (articleViewCount <$> article)
	let result = Article
			<$> titleResult
			<*> publishedResult
			<*> viewCountResult
		widget = $(widgetFile "article-editor-form")
	return (result, widget)

-- 新規登録
getArticleR :: Handler Html
getArticleR = do
	let
		header = "Article新規登録" :: Text
	(widget, enctype) <- generateFormPost $ articleForm Nothing
	defaultLayout $(widgetFile "article")

--新規登録処理のポスト
postArticleR :: Handler Html
postArticleR = do
	((result, widget),enctype) <- runFormPost $ articleForm Nothing
	let
		header = "Article新規登録" :: Text
	case result of
		FormSuccess article -> do
			--Postされたデータが正常な場合
			articleId <- runDB $ insert article
			redirect ArticleListR
		FormFailure _ -> do
			--不正な入力値のデータが送信された場合(必須項目が未入力等)
			setMessage "不正なデータが送信されました。"
			defaultLayout $(widgetFile "article")
		FormMissing -> defaultLayout [whamlet|データが送信されませんでした。 |]
		_ -> undefined

--更新
getArticleUpdateR :: ArticleId -> Handler Html
getArticleUpdateR articleId = do
	let
		header = "Article更新" :: Text
	article <- runDB $ get404 articleId  --更新対象のデータが存在しないと404エラー
	(widget, enctype) <- generateFormPost $ articleForm $ Just article
	defaultLayout $(widgetFile "articleUpdate.hamlet")

--更新処理のポスト
postArticleUpdateR :: ArticleId -> Handler Html
postArticleUpdateR articleId = do
	((result, widget),enctype) <- runFormPost $ articleForm Nothing
	let
		header = "Article更新" :: Text
	case result of
		FormSuccess article -> do
			--Postされたデータが正常な場合
			_ <- runDB $ do
				_ <- get404 articleId	   --更新対象のデータが存在しないと404エラー
				replace articleId article   --更新処理の実行
			redirect ArticleListR
		FormFailure _ -> do
			--不正な入力値のデータが送信された場合(必須項目が未入力等)
			setMessage "不正なデータが送信されました。"
			defaultLayout $(widgetFile "article")
		FormMissing -> defaultLayout [whamlet|データが送信されませんでした。 |]
		_ -> undefined

呼び出される更新画面を作成し、呼び出し元の一覧画面を修正して完成です。一覧画面には @{ArticleUpdateR articleId} のURLを埋め込んで修正用の画面に遷移させています。
articleIdはルートで定義したパスの#ArticleIdの部分の値です。

更新画面のView作成

templates/articleUpdate.hamlet

<h1>#{header}
<form action=@{ArticleUpdateR articleId} method="POST" enctype="#{enctype}">
	^{widget}
	<input type="submit" value="送信">

templates/articleList.hamlet

<h1>Article一覧画面
<a href="@{ArticleR}">新規登録
<table border="1px">
	<tr>
		<th>タイトル
		<th>公開日
		<th>ビュー数
		<th>
	$forall Entity articleId article <- articles
		<tr>
			<td>
				#{articleTitle article}
			<td>
				#{show $ articlePublished article}
			<td>
				$maybe count <- articleViewCount article
					#{count}
			<td>
				<a href="@{ArticleUpdateR articleId}">編集

Handlerの処理内容

Handler の実装を見ていきます。新規実装の処理と重複する箇所も多いです。まずはGETの処理から。

  • get404 で Id から更新対象のデータが存在するか確認しています。 get404 では Id を条件に対象データを取得しますが、データが存在しない場合は 404NotFound のエラーとなります。
  • 後は取得したデータを渡してフォームを生成します。新規登録の場合と同じがれです。

POSTの処理も同様です。

  • フォームから POST されたデータを受け取るまでは同様です。
  • 更新対象のデータを get404 で取得します。
  • replace で更新するデータと、更新対象の Id を渡してやります。キーに対応するエンティティが存在すれば置き換えて更新します。

以上が DB の更新処理でした。フォームの理解ができれば比較的簡単でした。できれば新規登録の画面と共通化したかったのですが、@{…} 動的に切り替えたかったのですが、やりたいようにできなかったので、ファイルごと分けました。

あとは次回データの削除機能を実装しておしまいです。

参考URL

Haskellカテゴリの最新記事