Phoenix 動作検証 (3)

memo

コンテナ関連について気になったので Dockerhub 探してみることに。

  • とりあえず elixir については image が存在している (elixir:1.16.1-slim を使用)

  • Phoenix は Dockerfile の中で mix で云々している

  • 蛇足ですが distillery は基本的に使わない (はず)

これデフォ、ってことで確認すすめます。参照しているエントリは以下です。

追記

見てるドキュメントが古そうなのでやり直します。以下はあまり参考にならないかと。

ソース確認

スキーマから。というか changeset とは何かと。

  @doc false
  def changeset(task, attrs) do
    task
    |> cast(attrs, [:content, :state])
    |> validate_required([:content, :state])
  end

ちなみにコンテキストでのデータ生成時に以下な形で呼び出しています。

  @doc """
  タスクを作成する。
  """
  def create_task(attrs \\ %{}) do
    %Task{}
    |> Task.changeset(attrs)
    |> Repo.insert()
  end

あと、Ecto.Changeset というものを import していますね。ググッてみたら以下が出てきました。

ええと、上の changeset の例だと

  • 構造体、修正な引数から

  • cat で Changeset を作って

  • validation しています
    という理解で良いのかしら。問題なければ Repo.insert に渡す情報が戻される、という事で。

コントローラも順に確認を。まず以下の部分。

  alias TodoPhoenix.Todo
  alias TodoPhoenix.Todo.Task

これは完全修飾なしで使います、って理解で良いのかしら。というか直上に use ってのもありますね。

use TodoPhoenixWeb, :controller

このあたりの意味を一度確認しておきたい。

  • use については コントローラーにて「モジュール定義の下の最初の行では、HelloWeb モジュールの using/1 マクロを呼び出しており、いくつかの便利なモジュールをインポートしています。」という記載があります

  • 別途 The ‘use’ Macro in Elixir. を確認のこと

で、lib/todo_phoenix_web.ex 見てみるに controller って手続きが定義されてますね。

  def controller do
    quote do
      use Phoenix.Controller,
        formats: [:html, :json],
        layouts: [html: TodoPhoenixWeb.Layouts]

      import Plug.Conn
      import TodoPhoenixWeb.Gettext

      unquote(verified_routes())
    end
  end

いくつかの便利なモジュールをインポート、ってのがこれ、って理解で良いはず。あと alias ですが alias, require, and import にて

alias Math.List

alias Math.List, as: List

と同義、って記載がありました。なるほど。以降の手続き定義の部分が以下。

  def index(conn, _params) do
    tasks = Todo.list_tasks()
    render(conn, "index.json", tasks: tasks)
  end

  def create(conn, %{"task" => task_params}) do
    case Todo.create_task(task_params) do
      {:ok, %Task{}} ->
        send_resp(conn, :created, "")
      {:error, _} ->
        send_resp(conn, :unprocessable_entity, "")
    end
  end

  def create(conn, _), do: send_resp(conn, :bad_request, "")
  • send_resp は body が無いレスポンスを戻したい場合に使う、とのこと

    • :created とか :unprocessable_entity とか :bad_request はステイタスのはず

  • あと create_task の戻りがどうなっているのか気になります

    • insert の戻り、なのか

そゆ意味では定義が以下、なんですが

  def create_task(attrs \\ %{}) do
    %Task{}
    |> Task.changeset(attrs)
    |> Repo.insert()
  end

そもそもこの %Task{} とは一体何なのか、確認必要。

  • Elixir Ecto のまとめ によると Ecto.Schema は DB テーブルを Elixir struct に map するために使われる、とのこと

    • なので上の create_task で使われている %Task{} は空の struct で

    • create で match させるのに使われているのは型の表現、という理解で良いのかしら (このあたり若干微妙なので再度アレを確認)

json を出力する view の作成も行なっています。

defmodule TodoPhoenixWeb.TaskView do
  use TodoPhoenixWeb, :view
  alias TodoPhoenixWeb.TaskView

  def render("index.json", %{tasks: tasks}) do
    %{data: render_many(tasks, TaskView, "task.json")}
  end

  def render("task.json", %{task: task}) do
    %{
      id: task.id,
      content: task.content,
      state: task.state
    }
  end
end

で、これが動かない。対処が以下。

  • lib/todo_phoenix_web.ex に view メソド追加

  • mix.exs に {:phoenix_view, "~> 2.0"}, 追加して mix deps.get 実行

で、以下実行してみるに落ちてます。

# curl http://localhost:4000/api/tasks

ちなみにルーティング定義については以下を追加してるのですがどうなのか。

  scope "/api", TodoPhoenixWeb do
    pipe_through :api

    resources "/tasks", TaskController, only: [:create, :index] # 追加
  end

routing 情報確認したら出力されてますね。

# mix phx.routes
  GET   /                                      TodoPhoenixWeb.PageController :home
  GET   /api/tasks                             TodoPhoenixWeb.TaskController :index
  POST  /api/tasks                             TodoPhoenixWeb.TaskController :create

コンソールには以下な出力が。

[error] GenServer #PID<0.874.0> terminating
** (UndefinedFunctionError) function TodoPhoenixWeb.TaskController.init/1 is undefined (module TodoPhoenixWeb.TaskController is not available)
    TodoPhoenixWeb.TaskController.init(:index)
    (phoenix 1.7.11) lib/phoenix/router.ex:484: Phoenix.Router.__call__/5
    (todo_phoenix 0.1.0) lib/todo_phoenix_web/endpoint.ex:1: TodoPhoenixWeb.Endpoint.plug_builder_call/2

確認してみるにコントローラなソースコード保存してませんでした。次に出てきたのは以下な不具合。

[error] GenServer #PID<0.776.0> terminating
** (ArgumentError) no "index" json template defined for TodoPhoenixWeb.TaskJSON  (the module does not exist)
    (phoenix_template 1.0.4) lib/phoenix/template.ex:248: Phoenix.Template.render_with_fallback/4
    (phoenix_template 1.0.4) lib/phoenix/template.ex:126: Phoenix.Template.render_to_iodata/4

なんかそもそも的に api の作り方がダウトな気がしてきたのでドキュメント見て修正。別途でドキュメントの方法でやり直す。

この記事が気に入ったらサポートをしてみませんか?