技術メモ

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

Phoenix入門 (第14章 Mix Tasks その1)

f:id:ysmn_deus:20190219130922p:plain

どうも、靖宗です。
今回はMix Tasksということでmix phx.hogehogeのコマンドあたりの説明でしょうか。

Mix Tasks

Phoenix Specific Mix Tasks

Phoenixで使いそうなコマンド一覧があります。

mix local.phx          # Updates the Phoenix project generator locally
mix phx                # Prints Phoenix help information
mix phx.digest         # Digests and compresses static files
mix phx.digest.clean   # Removes old versions of static assets.
mix phx.gen.cert       # Generates a self-signed certificate for HTTPS testing
mix phx.gen.channel    # Generates a Phoenix channel
mix phx.gen.context    # Generates a context with functions around an Ecto schema
mix phx.gen.embedded   # Generates an embedded Ecto schema file
mix phx.gen.html       # Generates controller, views, and context for an HTML resource
mix phx.gen.json       # Generates controller, views, and context for a JSON resource
mix phx.gen.presence   # Generates a Presence tracker
mix phx.gen.schema     # Generates an Ecto schema and migration file
mix phx.gen.secret     # Generates a secret
mix phx.new            # Creates a new Phoenix application
mix phx.new.ecto       # Creates a new Ecto project within an umbrella project
mix phx.new.web        # Creates a new Phoenix web project within an umbrella project
mix phx.routes         # Prints all routes
mix phx.server         # Starts applications and their servers

細かい機能はPhoenix公式ドキュメントの「MIX TASKS」を見れば良さそうです。
幾つか簡単に取り上げてくれているので、一応目を通しておきます。

mix phx.new

言わずと知れたPhoenixプロジェクトを生成する際に使うコマンドです。
--no-ecto--no-webpackというオプションをつける事でEctoの実装を無くしたり、Webpackの実装を無くしたりできるそうですが、基本的には必要なんじゃないでしょうか。
APIサーバーとして機能するときはWebpackは不要?)

実際に生成するプロジェクト名はスネークケースがいいっぽいです。

> mix phx.new task_tester

相対パスでも絶対パスでもヨシ。

> mix phx.new ../task_tester
> mix phx.new /Users/me/work/task_tester

mix phx.newでプロジェクトを生成するとアプリケーション名はプロジェクト名(上記だとtask_tester)になります。
もしアプリケーション名を変更したい場合はmix phx.new task_tester --app hello--appオプションを利用するそうです。

mix.exsでアプリケーション名が変更されています。

defmodule Hello.MixProject do
  use Mix.Project

  def project do
    [app: :hello,
     version: "0.1.0",
...

このアプリケーション名を変更するとモジュール名などの接頭辞が変わるようです。

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

--appオプションでhelloを設定したのでモジュール名がHelloから始まってます。
lib/フォルダ以下のディレクトリやファイル名なども変わります。

基本は--appでいいような気はしますが、「モジュール名の接頭辞だけ変えたい!」という場合には--moduleオプションで指定出来るようです。

$  mix phx.new task_tester --module Hello
* creating task_tester/config/config.exs
* creating task_tester/config/dev.exs
* creating task_tester/config/prod.exs
* creating task_tester/config/prod.secret.exs
* creating task_tester/config/test.exs
* creating task_tester/lib/task_tester/application.ex
* creating task_tester/lib/task_tester.ex
* creating task_tester/lib/task_tester_web/channels/user_socket.ex
* creating task_tester/lib/task_tester_web/views/error_helpers.ex
* creating task_tester/lib/task_tester_web/views/error_view.ex
* creating task_tester/lib/task_tester_web/endpoint.ex
* creating task_tester/lib/task_tester_web/router.ex
* creating task_tester/lib/task_tester_web.ex
* creating task_tester/mix.exs
* creating task_tester/README.md
* creating task_tester/.gitignore
* creating task_tester/test/support/channel_case.ex
* creating task_tester/test/support/conn_case.ex
* creating task_tester/test/test_helper.exs
* creating task_tester/test/task_tester_web/views/error_view_test.exs
* creating task_tester/lib/task_tester_web/gettext.ex
* creating task_tester/priv/gettext/en/LC_MESSAGES/errors.po
* creating task_tester/priv/gettext/errors.pot
* creating task_tester/lib/task_tester/repo.ex

mix.exsは下のようなかんじ。

defmodule Hello.MixProject do
  use Mix.Project

  def project do
    [app: :task_tester,
...

アプリケーション名はtask_testerのままで、接頭辞のみがHelloとなっています。
ややこしいことになりそうなので、変えたいなら--appを使った方が良さそうです。

mix phx.gen.html

これはContextあたりで使いました。HTMLでのresourcerouter.exresource指定する奴)を生成する際に便利なコマンドです。
Webレイヤーの実装(コントローラ、ビュー、テンプレート)はもちろん、EctoのマイグレーションファイルやContextも生成してくれます。

このコマンドは引数が多くてややこしいですが、その中身は至ってシンプルで
mix phx.gen.html Context名 スキーマ名 リソース名 スキーマのリスト(項目名:型)
です。

$ mix phx.gen.html Blog Post posts body:string word_count:integer
* creating lib/hello_web/controllers/post_controller.ex
* creating lib/hello_web/templates/post/edit.html.eex
* creating lib/hello_web/templates/post/form.html.eex
* creating lib/hello_web/templates/post/index.html.eex
* creating lib/hello_web/templates/post/new.html.eex
* creating lib/hello_web/templates/post/show.html.eex
* creating lib/hello_web/views/post_view.ex
* creating test/hello_web/controllers/post_controller_test.exs
* creating lib/hello/blog/post.ex
* creating priv/repo/migrations/20170906150129_create_posts.exs
* creating lib/hello/blog/blog.ex
* injecting lib/hello/blog/blog.ex
* creating test/hello/blog/blog_test.exs
* injecting test/hello/blog/blog_test.exs

mix系のコマンドに一般的に言えることですが、次に何やったらいいか注釈がでてくれます。

Add the resource to your browser scope in lib/hello_web/router.ex:

    resources "/posts", PostController

Remember to update your repository by running migrations:

    $ mix ecto.migrate

ルーティングの設定とマイグレーションしろよ!と出ています。基本これだけでリソースが作成できます。

大体無いとは思うんですが、Contextいらないよ!って時(Bootstrapのテストなど、なんらかのテストに使う?)は--no-contextというオプションがあるそうです。
活用法があまり思い浮かばないので省略。 同様に--no-schemaオプションもあり。

mix phx.gen.json

こちらは使ったことはないですが、見た目からして上記のJSON版といったところでしょうか。

$ mix phx.gen.json Blog Post posts title:string content:string
* creating lib/hello_web/controllers/post_controller.ex
* creating lib/hello_web/views/post_view.ex
* creating test/hello_web/controllers/post_controller_test.exs
* creating lib/hello_web/views/changeset_view.ex
* creating lib/hello_web/controllers/fallback_controller.ex
* creating lib/hello/blog/post.ex
* creating priv/repo/migrations/20170906153323_create_posts.exs
* creating lib/hello/blog/blog.ex
* injecting lib/hello/blog/blog.ex
* creating test/hello/blog/blog_test.exs
* injecting test/hello/blog/blog_test.exs

コマンドの仕様もほぼhtmlと変わらないようです。
コマンド実行後の注釈はちょっと変わってきています。

Add the resource to your :api scope in lib/hello_web/router.ex:

    resources "/posts", PostController, except: [:new, :edit]


Remember to update your repository by running migrations:

    $ mix ecto.migrate

:new:editのアクションを除外しています。
JSONなので新規生成画面と編集画面がないためでしょう。HTTPリクエストなどで直接:create:updateを実行するということでしょう。

htmlと同様に--no-context--no-schemaオプションもあり。

mix phx.gen.context

Contextの章でAccountsにCredentialを追加するときに使いました。
追加するように使った場合はinjecting lib/hello/accounts.exというように既存のContextに追記する形で生成されましたが、Contextのみ生成したい場合にも利用できるようです。
主な使用方法はhtmljsonの時と同じ。

$ mix phx.gen.context Accounts User users name:string age:integer
* creating lib/hello/accounts/user.ex
* creating priv/repo/migrations/20170906161158_create_users.exs
* creating lib/hello/accounts/accounts.ex
* injecting lib/hello/accounts/accounts.ex
* creating test/hello/accounts/accounts_test.exs
* injecting test/hello/accounts/accounts_test.exs

mix phx.gen.schema

HTMLやJSONのリソースも作らず、Contextも不要というレアケース用?でもコマンドが用意されてるってことは必要なタイミングがあるのかも。
コマンド引数はhtmljsonからContext名を省略したようなかんじ。

$ mix phx.gen.schema Accounts.Credential credentials email:string:unique user_id:references:users
* creating lib/hello/accounts/credential.ex
* creating priv/repo/migrations/20170906162013_create_credentials.exs

mix phx.gen.channel

Channelを生成するためのコマンド。Channelの章では手動で作成しましたが、コマンドでも生成してくれるようです。
引数は純粋にチャンネル名のみ。

$ mix phx.gen.channel Room
* creating lib/hello_web/channels/room_channel.ex
* creating test/hello_web/channels/room_channel_test.exs

ちゃんとメッセージも出してくれます。

Add the channel to your `lib/hello_web/channels/user_socket.ex` handler, for example:

    channel "rooms:lobby", HelloWeb.RoomChannel

mix phx.gen.presence

これはPresenceの章で使いました。
一応モジュール名を指定できますが、省略すればPresenceで作成されます。

$ mix phx.gen.presence
* creating lib/hello_web/channels/presence.ex

こちらもきちんと注釈を付けてくれます。

Add your new module to your supervision tree,
in lib/hello/application.ex:

    children = [
      ...
      HelloWeb.Presence
    ]

You're all set! See the Phoenix.Presence docs for more details:
http://hexdocs.pm/phoenix/Phoenix.Presence.html

mix phx.routes

Routingの章で利用しました。
コマンドを実行すればルーティングルールが表示されます。

$ mix phx.routes
page_path  GET  /  TaskTester.PageController.index/2

ルーティングファイルが2個以上あるときは、ルーティングファイル名を指定するとソイツだけみれるようです。

$ mix phx.routes TaskTesterWeb.Router
page_path  GET  /  TaskTesterWeb.PageController.index/2

mix phx.server

サーバーを立ち上げるコマンド。DoesNotExistオプションとかもあるけどよくわかんない。(本来は「DoesNotExist」が必要だけど省略されてる?)
iexで立ち上げたい時はiex -S mix phx.serverを実行してやればよいそうで。

$ iex -S mix phx.server
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]

[info] Running TaskTesterWeb.Endpoint with Cowboy on port 4000 (http)
Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>

これ地味に便利そうですね。

mix phx.digest

静的ファイル(static assets)の名前にダイジェスト(MD5)を付与し、圧縮するコマンドだそうです。
機能的にほぼデプロイ用(改ざん防止、転送量軽減)と考えて問題無さそうです。

assets/ディレクトリにあるファイルに処理を行い、デフォルトではpriv/staticにコピーするようです。
出力されるファイルの場所や処理するファイルの場所を指定したいときは引数で調整可能。

$ mix phx.digest priv/static -o www/public
Check your digested files at 'www/public'.

コンフィグに:を指定すると圧縮するファイルの対象を変更できるようです。

config :phoenix, :gzippable_exts, ~w(.js .css)

役割的にconfig/config.exsあたりにでも書けば良いのでしょうか。

デプロイは別の章でやるので、そのときにもう一度確認します。

飛ばし飛ばしやってるつもりが結構長くなったのでまた次回!