技術メモ

プログラミングとか電子工作とか

Phoenix入門 (第7章 Controllers その1)

f:id:ysmn_deus:20190219130922p:plain

どうも、靖宗です。 今回はControllersということで、コントローラの話です。
ルーティングのところで一通りは把握している所ですが、少々深掘りしていきましょう。

今のところ、Phoenixの作業は

  1. mix phx.new project_nameでプロジェクトを作成
  2. データベース関連の操作(データベース用意したり設定書いたりmix ecto.createしたり)
  3. router.exを編集してルーティングを調整
  4. controllersにコントローラを追加
  5. viewsにビューを追加
  6. 必要であればtemplatesにテンプレートを追加(JSONならたぶんいらない)
  7. 3~6を繰り返し

みたいな流れになりそうです。
コントローラは機能としてはルーティングとレンダリングの橋渡しをする箇所を担っています。

Phoenixプロジェクトを開始した際に入っているlib/hello_web/controllers/page_controller.exには下記のように書かれています。

defmodule HelloPhoenixWeb.PageController do
  use HelloPhoenixWeb, :controller

  def index(conn, _params) do
    render(conn, "index.html")
  end
end

コントローラを追加していく時はコレをベースに作成していくのがよさそうです。

また、コントローラもPlugで実装されているようです。

Actions

コントローラでActionと呼称されているものがありますが、ただの関数です。アクションと関数をわざわざ言い換える必要も無いのですが、アクション関数の目的がレンダリングすることであり、「○○モジュールのレンダリングする関数」と言うのがめんどいのでアクションと呼んでいるに過ぎないのでしょう。
PageControllerにデフォルトで備わっているアクションは:indexで、ルーティングファイルから下記のように呼び出されています。

get "/", PageController, :index

テスト用には:testというアクションが想定されているようです。

get "/", PageController, :test

コントローラにテストを追加するならこんなかんじ

defmodule HelloPhoenixWeb.PageController do
  use HelloPhoenixWeb, :controller
  ...

  def test(conn, _params) do
    render(conn, "index.html")
  end
end

まぁ、現段階ではテストになってないんですが。

アクションの命名自体は自由だそうですが、ルーティングの章でResourcesをやりました。これを鑑みると下記のアクション名は機能をResourcesに揃えておくのが望ましいでしょう。

  • index
    • リソースのアイテムを全表示する
  • show
    • IDで識別されるアイテムを表示する
  • new
    • 新しいアイテムを作成する画面を表示する
  • create
    • 新しいアイテムを作成する変数を受けてデータベースなどに保存する(表示自体はリダイレクト?)
  • edit
    • 編集するIDの変数を取り出す+編集できるフォームを表示する
  • update
    • 編集するアイテムの変数を受けてデータベースなどに上書き保存する
  • delete
    • 削除するIDを受けてデータベースから削除する(確認画面なんかも出した方がいい?)

アクションは基本的に2つ引数をとります。1個目はconnという事でPlugのところで出てきている接続情報(%Plug.Conn{})です。
これはコントローラがPlugで実装されているからでしょう。

2個目の引数はparamsで、必要に応じてHTTPリクエストからパラメータを取り出すマップとなっています。
Adding Pagesの章でやりましたが、ルーティングの際に

get "/hello/:messenger", HelloController, :show

と書かれている場合はリクエストが来た場合にparams"messenger"というキーで値が入っています。
例えばhttp://localhost:4000/hello/hogefugaというアドレスにアクセスがあった場合には、paramsには"messenger"というキーに"hogefuga"が値として渡されます。
これをコントローラで

defmodule HelloPhoenixWeb.PageController do
  ...

  def show(conn, %{"messenger" => messenger}) do
    render(conn, "show.html", messenger: messenger)
  end
end

というふうに、パターンマッチングで受けるのがPhoenixの習わしっぽいです。

:indexアクションの様にパラメータが不要な際は_paramsと”関数の実行に関わりの無い引数”としておくのが良いでしょう。(Elixirのならわし)

Gathering Data

データのストア(記録、読み出しなど)機能はPhoenixの機能としては実装してないようです。
それもそのはず、EctoというデータベースラッパーがElixirには存在しているらしく、そちらを使うと良いよ!と記載があります。
なので、基本的には

  1. リクエストが来てコントローラのアクションが呼び出される
  2. アクション内でEctoやETS、OTPで作ったデータストアでデータを呼び出す
  3. レンダリング関数を呼び出してビューモジュールで処理

という流れになると思います。
実際に開発を進めるに当たってEctoも重要になってきそうですので、また別途記事にしたいと思います。

hexdocs.pm

Flash Messages

Flash Messagesという機能があるようです。フロントでもちょいちょい見たような?
SPAなどでよくある「ログインに失敗しました」みたいなのがぴょこっと出てきて画面遷移しない時とかに使う奴だと思います。

コントローラを使える状態であればput_flash/3get_flash/2でメッセージのやりとりができるようです。サンプルを見てみます。

defmodule HelloPhoenixWeb.PageController do
  ...
  def index(conn, _params) do
    conn
    |> put_flash(:info, "Welcome to Phoenix, from flash info!")
    |> put_flash(:error, "Let's pretend we have an error.")
    |> render("index.html")
  end
end

put_flash/3の第一引数はパイプラインですので接続情報、第二引数はメッセージのキー、第三引数はメッセージのバリューという関数でしょう。
特にキー名などの制約はないようですが、:info:errorはよく使われるようです。

表示するときはテンプレートでget_flash/2を使うようです。

<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>

第一引数が接続情報、第二引数がキーというかんじです。
他にもclear_flash/1という関数もあるようですが、このへんはFlash Messagesを使いたくなったら検討しましょう。
なんとなくフロント側で処理する方がスッキリする気がします。

Controllersちょっと長いので一旦ここで区切ります。