8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

一人LiveViewAdvent Calendar 2021

Day 2

Phoenixで作るGPS Logging System 2 CRUDの中身 part1

Last updated at Posted at 2021-12-01

はじめに

ひとりLiveView Advent Calendar の2日目の記事です

この記事はElixir Conf US 2021発表したシステムの構築と関連技術の解説を目的とした記事です

今回は以下の4つの解説します

  • phx.gen.live で作成されたもの
  • LiveViewのRouting
  • handle_params
  • handle_event

phx.gen.live で作成されたもの

以下は phx.gen.liveを実行したときの端末ログです

* creating lib/live_logger_web/live/map_live/show.ex
* creating lib/live_logger_web/live/map_live/index.ex
* creating lib/live_logger_web/live/map_live/form_component.ex
* creating lib/live_logger_web/live/map_live/form_component.html.heex
* creating lib/live_logger_web/live/map_live/index.html.heex
* creating lib/live_logger_web/live/map_live/show.html.heex
* creating test/live_logger_web/live/map_live_test.exs
* creating lib/live_logger_web/live/modal_component.ex
* creating lib/live_logger_web/live/live_helpers.ex
* creating lib/live_logger/loggers/map.ex
* creating priv/repo/migrations/20211118095356_create_maps.exs
* creating lib/live_logger/loggers.ex
* injecting lib/live_logger/loggers.ex
* creating test/live_logger/loggers_test.exs
* injecting test/live_logger/loggers_test.exs
* creating test/support/fixtures/loggers_fixtures.ex
* injecting test/support/fixtures/loggers_fixtures.ex
* injecting lib/live_logger_web.ex

Add the live routes to your browser scope in lib/live_logger_web/router.ex:

    live "/maps", MapLive.Index, :index
    live "/maps/new", MapLive.Index, :new
    live "/maps/:id/edit", MapLive.Index, :edit

    live "/maps/:id", MapLive.Show, :show
    live "/maps/:id/show/edit", MapLive.Show, :edit

creatingだけを分類するとこんな感じになります

Liveview

①一覧ページ

  • creating lib/live_logger_web/live/map_live/index.ex
  • creating lib/live_logger_web/live/map_live/index.html.heex

②詳細ページ

  • creating lib/live_logger_web/live/map_live/show.ex
  • creating lib/live_logger_web/live/map_live/show.html.heex

③モーダルで表示するform

  • creating lib/live_logger_web/live/map_live/form_component.ex
  • creating lib/live_logger_web/live/map_live/form_component.html.heex

④汎用modal

  • creating lib/live_logger_web/live/modal_component.ex
  • creating lib/live_logger_web/live/live_helpers.ex

コントローラーに当たる箇所が.exファイル、ビューに当たるのが.heexです
htmlがシンプルな場合は .ex内のrender関数内で~H(シジル)で囲って記述することもできます

def render(assigns) do
  ~H"""
  <h1>Title</h1>
  """
end

Model

  • creating priv/repo/migrations/20211118095356_create_maps.exs ①
  • creating lib/live_logger/loggers/map.ex ②
  • creating lib/live_logger/loggers.ex ③

①migrationファイル
②スキーマ、バリデーション周り
③クエリ類

Test

  • creating test/live_logger_web/live/map_live_test.exs
  • creating test/live_logger/loggers_test.exs
  • creating test/support/fixtures/loggers_fixtures.ex

テストもバックエンド、フロントエンド両方作成してくれます
本連載ではmodel,testのコードにはあまり触れずLiveViewを主に解説します

Router

Router周りの解説をしていきます
map_live/index.exを参考に見ていきましょう

lib/live_logger_web/router.ex
defmodule LiveLoggerWeb.Router do
  ...
  scope "/", LiveLoggerWeb do
    live "/maps", MapLive.Index, :index
    live "/maps/new", MapLive.Index, :new
    live "/maps/:id/edit", MapLive.Index, :edit

    live "/maps/:id", MapLive.Show, :show
    live "/maps/:id/show/edit", MapLive.Show, :edit
  end
end
lib/live_logger_web/live/map_live/index.ex
defmodule LiveLoggerWeb.MapLive.Index do
  def mount(_params, _session, socket) do
  ...
  end

  @impl true
  def handle_params(params, _url, socket) do
    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
  end

  defp apply_action(socket, :edit, %{"id" => id}) do
  ...
  end

  defp apply_action(socket, :new, _params) do
  ...
  end

  defp apply_action(socket, :index, _params) do
  ...
  end
end

LiveViewのroutingは以下のように記述します。
SPA寄りな書き方になるで通常のCRUDとは違いますが似たように書くことができます

live "/maps", MapLive.Index, :index

/maps -> url
MapLive.Index -> 使用するLiveView Module
:index -> socket.assigns.live_actionに入るパラメーター

live "/maps", MapLive.Index, :new

/maps/newにアクセスした場合にsocket.assigns.live_action:newを入れる

live "/maps/:id/edit", MapLive.Index, :edit

/maps/:id/editにアクセスした場合にsocket.assigns.live_action:editを入れる
:idは以下paramsのMapのkeyになるので、
live_action:editでparamsに"id"キーを持つ以下の関数としてパターンマッチする

  def handle_params(params, _url, socket) do
    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
  end

  defp apply_action(socket, :edit, %{"id" => id}) do
  ...
  end

なので
live "/maps/:id/edit", MapLive.Index, :edit
上記の:id:hogeに変えるとパターンマッチが失敗してエラーになり
defp apply_action(socket, :edit, %{"hoge" => id})
で合わせると正常に動くようになります

handle_params

handle_paramsはmount後に実行されるもので
params, url, socketを引数に処理を実行し{:noreply, socket}を返す関数です
今回はapply_actionという関数を実行して live_actionを元に:index :edit :newに振り分けています
apply_actionはそれぞれ以下の処理を行っています

  • :index -> formを初期化, titleをListing Mapに設定
  • :new -> formに新しいchangesetを作成, titleをNew Mapに設定
  • :edit -> formにparamsのidで取得したデータをセット, titleをEdit Mapに設定

なのでrouterの
live "/maps", MapLive.Index, :new
live "/maps", MapLive.Index, :hogeとかにするとマッチするapply_actionがなくエラーになります。
これに対してエラーで落とすのではなく、404ページにリダイレクトしたい場合は以下のような関数をindexの下に追加します。
一応警告は出ますが、editの上に追加するとaction, paramsに関係なく実行されて他の関数にマッチしなくなるので関数の順番には注意しましょう

defp apply_action(socket, _action, _params) do 
  push_redirect(socket, to: "/404")
end

CRUD画面ではURLと画面を合わせるためにhandle_paramslive_actionを元に振り分けていますが、単純なLiveViewではmount時に一覧を取得してsocketassignすることが一般的です。

handle_paramsの他の用途はmaps/:idでアクセスしたが自分が管理しているmap以外だった場合は403errorを返すとかが考えられます

handle_event

handle_eventはphx-click, phx-change, phx-submitなどで指定されたイベント名を引数として関数を実行します
CRUD画面では以下が実装されています

  • 削除ボタンをクリック時 -> handle_event("delete", params, socket)
  • フォームの内容が変更された時 -> handle_event("validate", params, socket)
  • フォームがsubmitされたとき -> handle_event("save", params, socket)

handle_event内でDBへの保存や削除を行えるため新たにAPIを生やす必要がなくなります
また別の記事で解説しますが JS側からpushEvent関数を実行することでLiveView側のhandle_eventを実行することも可能です

最後に

長くなってきたので一旦ここで切ろうと思います
次はmodalに関して解説します

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?