elm

elmでwebアプリ作成13 〜 施設情報を編集してDBに反映

前回は、施設情報を編集してモデルを更新するところまで作りました。

今回は編集内容をデータベースに反映させる処理です。

このコミットです。

コミット単位で記事を書く方法、良いですね。この記事を読んでくれている人は今の所誰もいないかもしれませんが、コミット内容の説明になるので、あとで自分で見返す時にもわかりやすいです。githubにはこの記事のリンクを貼っていないから辿れませんが。

流れとしては、
施設情報の編集

“save”ボタン

データベースに反映するためのPATCHリクエスト

成功したらモデルをアップデート、失敗したらそのまま

ビュー

となります。以下の図のような流れです(公式チュートリアルの図なので関数名は全然違います)。

ポイントは、この一連の処理でメッセージを2回使っているところです。1回目は、save -> リクエストのところです。2回目は、リクエスト結果 -> モデルアップデートのところです。データベースへの反映がなんらかの理由で失敗したときにモデルをアップデートしないようにするためです。ただ実は、今回は意味のない仕様になっています。なぜなら各フィールドの値を変更するたびにモデルをアップデートしているからです。全部のフィールドの情報を編集してから、最後に一回だけリクエストを送るようにしたかったのでこのようにしました。もし、入力するたびにDBへの反映まで行うなら、上記の仕様は意味を持ちます。


src/Commands.elmの編集

Httpリクエストを送るためのコマンドです。saveボタンを押してメッセージが送信されると、saveFacilityCmdコマンドが発行されます。このコマンドは、DBに反映するためのsaveFacilityRequestを送り、リクエスト結果をOnFacilitySaveメッセージに乗せます。

-- FacilityデータをJSONにエンコードするための追加インポート
import Json.Encode as Encode

-- FacilityをJSONにエンコード
facilityEncoder : Facility -> Encode.Value
facilityEncoder facility =
 let
     attributes =
         [ ("id", Encode.string facility.id)
         , ("name", Encode.string facility.name)
         , ("opening", openingEncoder facility.opening)
         , ("address", Encode.string facility.address)
         , ("postcode", Encode.string facility.postcode)
         , ("web_site", Encode.string facility.web_site)
         , ("description", Encode.string facility.description)
         ]
 in
     Encode.object attributes

openingEncoder : Opening -> Encode.Value
openingEncoder opening =
 let
     attributes =
         [ ("open", Encode.string opening.open)
         , ("close", Encode.string opening.close)
         ]
 in
     Encode.object attributes

-- src/Update.elmから呼ばれるコマンド
saveFacilityCmd : Facility -> Cmd Msg
saveFacilityCmd facility =
 saveFacilityRequest facility
     |> Http.send Msgs.OnFacilitySave

-- 編集したFacilityデータをDBに反映するためのPATCHリクエスト
saveFacilityRequest : Facility -> Http.Request Facility
saveFacilityRequest facility =
 Http.request
 { body = facilityEncoder facility |> Http.jsonBody
 , expect = Http.expectJson facilityDecoder
 , headers = []
 , method = "PATCH"
 , timeout = Nothing
 , url = saveFacilityUrl facility.id
 , withCredentials = False
 }

-- リクエストURL
saveFacilityUrl : FacilityId -> String
saveFacilityUrl facilityId =
 fetchFacilitiesUrl ++ "/" ++ facilityId

src/Facilities/SingleEdit.elmの編集

saveボタンを押した時に、SaveUpdatedFacilityメッセージが送信されるようにします。

-- 変更前(editForm関数の一部)
, button [] [ text "Submit"]

-- 変更後
, button [onClick (Msgs.SaveUpdatedFacility model)] [ text "Save"]

src/Msgs.elmの編集

DB反映リクエスト用のメッセージとその後のモデルアップデート用メッセージを定義します。

-- 追加インポート
import Http

-- メッセージを2つ追加
| SaveUpdatedFacility Facility
| OnFacilitySave (Result Http.Error Facility)

src/Update.elmの編集

-- 追加インポート
import Commands exposing (saveFacilityCmd)

-- 定義したメッセージに対応するアップデート処理を追加
-- リクエスト結果を受けるときは、OkとErrでそれぞれ定義
Msgs.SaveUpdatedFacility facility ->
    ( model, saveFacilityCmd facility)
Msgs.OnFacilitySave (Ok facility) ->
    ( updateFacility model facility, Cmd.none )
Msgs.OnFacilitySave (Err error) ->
    let _ = Debug.log "OnFacilitySave error:" error in
    ( model, Cmd.none )

以上で、DB反映処理ができました。ちなみに、この編集ページは今こんな感じになっています。
CSSを書いていないので、とてもつまらない画面です。basscssを使えるようにしているので、自分で書かなくてもクラスを書けば色々やってくれるはずです。そしてこの記事のコミット時点では、saveボタンもまだcss適用前の味気ないボタンですので。

今の状態では、saveボタンを押した時にちゃんと保存(DB反映)されたのかどうかがわからないため、次回はそのステータスを表示するようにしていきます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です