Phoenix Framework Guide をなんとなく訳してみた③ Adding Pages


全体へのリンクは以下
[Phoenix Framework Guide をなんとなく訳してみた① Overview](http://qiita.com/rtbt525/items/afbf666e0c026c5658f4)

--

#ページの追加

ここではPhoenixアプリケーションに２つのページを追加します。ひとつは単なる静的なページ、もうひとつは入力されたURLからパスの一部を取り出し、テンプレートに渡して表示させます。その前に、Phoenixアプリケーションの基本的なコンポーネントであるRouter, Controllers, View そして Templates について知っておきましょう。

新しいPhoenixアプリケーションを生成した際、トップレベルのディレクトリ構成は以下のようになっています。

```
├── _build
├── config
├── deps
├── lib
├── priv
├── test
├── web
```

このガイドの中で最も作業をするフォルダは```web```ディレクトリでしょう。展開してみると以下のようになっています。

```
├── channels
├── controllers
│   └── page_controller.ex
├── models
├── router.ex
├── templates
│   ├── layout
│   │   └── application.html.eex
│   └── page
│       └── index.html.eex
└── views
|   ├── error_view.ex
|   ├── layout_view.ex
|   └── page_view.ex
└── web.ex
```

controllers, templates, viewsディレクトリのすべてのファイルが前のガイドで見た"Welcome to Phoenix!"のページを構成しています。コードの一部分を簡単に再利用する方法について見ていきましょう。

アプリケーションの静的な資源はcss, image, jsの各ファイルごとにすべて```priv/sttic```ディレクトリ内に存在します。```web/static```ディレクトリ内にビルドフェーズで必要な資源を配置すると、そのソースファイルはビルドする際にそれぞれ```app.js/app.css```としてまとめられ、```priv/static```ディレクトリ内に配置されます。ここまでなにも変更していませんが、後学のためこのことを知っておくのは良いことでしょう。

```
priv
└── static
    └── images
        └── phoenix.png
```

```
web
└── static
    ├── css
    |   └── app.css
    ├── js
    │   └── app.js
    └── vendor
        └── phoenix.js
        
```


それから```lib```ディレクトリとその中のファイルについても知らなくては行けません。```lib/hello_phoenix/endpoint.ex```がアプリケーションのエンドポイントとなり、```lib/hello_phoenix.ex```がアプリケーションファイル（アプリケーションとその管理下のツリーの始点）となります。


```
lib
├── hello_phoenix
|   ├── endpoint.ex
│   └── repo.ex
└── hello_phoenix.ex
```

予習はもう十分です。それでは最初の新しいPhoenixのページについて進めて行きましょう！

##Routeの作成（静的なページ）
Routeはcontroller/actionのペアに対して固有のHTTPの動作/パスのペアをマップし、それらの処理を実行します。
Phoenixは新しいアプリケーションを作成する際に```Web/router.ex```というrouterファイルを生成します。このセクションではこのファイルについて作業していきます。

[Up And Running](http://www.phoenixframework.org/v0.13.1/docs/up-and-running)（[Phoenix Framework Guide をなんとなく訳してみた② Up And Running](http://qiita.com/rtbt525/items/d65efc631a1661c2686d)）で以前見た"Welcome"ページのRouteは以下のようになっています。

```
get "/", PageController, :index
```

このrouteが何を意味するのか整理してみましょう。
[http://localhost:4000/](http://localhost:4000/)でアクセスすると、ルートパスに対してHTTPのGETリクエストが発行されます。その際、すべてのリクエストは```web/controllers/page_controller.ex```に定義された```HelloPhoenix.PageController```モジュールのindex関数で取り扱いますということを意味しています。

このガイドではブラウザから[http://localhost:4000/hello](http://localhost:4000/hello)にアクセスされた際に、単純に"Hello World, from Phoenix!"と表示するだけのものを作成していきます。

まずページを作成し、そのrouteを定義する必要があります。早速テキストエディタで```Web/router.ex```を開いてみましょう。ファイルは以下のようになっています。

```
defmodule HelloPhoenix.Router do
  use HelloPhoenix.Web, :router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
  end

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/", HelloPhoenix do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
  end

  # Other scopes may use custom stacks.
  # scope "/api", HelloPhoenix do
  #   pipe_through :api
  # end
end
```

さしあたり、ここでは```pipeline```や```scope```の使い方は無視してrouteの追加に焦点を当てます（もしもそれらについて気になるようであれば[Routing Guide](http://www.phoenixframework.org/v0.13.1/docs/routing)でそのトッピクスを説明しています）

```HelloPhoenix.HelloController```の```index```アクションと```/hello```に対する```GET```リクエストをマップするrouteをRouterに追加します（```HelloPhoenix.HelloController```はこの後すぐに作成します）。

```
get "/hello", HelloController, :index
```

```router.ex```の```scope "/"```ブロックは現在以下のようになっています。

```
scope "/", HelloPhoenix do
  pipe_through :browser # Use the default browser stack

  get "/", PageController, :index
  get "/hello", HelloController, :index
end
```

##Controllerの作成（静的なページ）
ControllerはElixirのモジュールとして、actionはElixirの関数として定義されています。actionの目的はデータをまとめ、レンダリングに必要なタスクを実行することです。routeには```HelloPhoenix.HelloController```モジュールの```index/2```アクションが必要なことを明示します。

それを実現するために、新たに```web/controllers/hello_controller.ex```を以下のように作成してください。

```
defmodule HelloPhoenix.HelloController do
  use HelloPhoenix.Web, :controller

  plug :action

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

```use HelloPhoenix.Web, :controller```や```plug :action```について議論するのは[Controllers Guide](http://www.phoenixframework.org/v0.13.1/docs/controllers)まで保留にしておきます。```index/2```アクションに注目してください。

コントローラのアクションはすべて2つの引数を取ります。一つ目は```conn```でリクエストについての大量のデータを保持する構造体です。２つ目の```params```はリクエストパラメータです。ここでは```params```は使いません。それから```_```を使うとコンパイルできないので気をつけてください。

このアクションのコアとなる部分は```render conn, "index.html"```です。これはPhoenixに対して```index.html.eex```テンプレートを見つけて呼び出し、レンダリングするように指示しています。Phoenixはコントローラの名前にちなんで命名されたディレクトリから要求されたテンプレートを探します。ここでは```web/template/hello```です。

一言：```render conn, :index```のようにテンプレートの名前としてatomを使った場合、前方一致するものがテンプレートとして選択されてしまいます（例えば```index.html```と```index.json```など）

レンダリングの責任を持つモジュールはViewです。次のセクションで新たに一つ作ってみます。

##Viewの作成（静的なページ）
PhoenixのViewはいくつかの重要な役割を担います。Viewはテンプレートを解釈して表現します。そしてコントローラから受け取った生のデータと予め準備されたテンプレートを使用してプレゼンテーションレイヤーとして振る舞います。生のデータを変換する関数はViewに定義されます。

例えば、ユーザを表す情報として```first_name```フィールドと```last_name```フィールドがあるデータ構造を持っており、テンプレートに対して、ユーザのフルネームを表示したいとします。それらのフィールドの値を結合してフルネームとするコードをテンプレートに書くこともできますが、Viewにそのような動作をする関数を書いてテンプレートから呼び出すほうがよりよいアプローチです。その結果より綺麗で読みやすいテンプレートとなります。

```HelloController```からテンプレートをレンダリングするために、```HelloView```が必要となります。ここでは名前に重要な意味があり、ControllerとViewで名前の最初の部分を合わせなくてはなりません。それではViewの詳細な内容については後にして、ひとまず空のファイルを作成しましょう。```web/views/hello_view.ex```を作成したら以下のように編集してください。

```
defmodule HelloPhoenix.HelloView do
  use HelloPhoenix.Web, :view
end
```

##Templateの作成（静的なページ）
Phoenixのtemplateはまさに"テンプレート"であり、どんなデータも渡すことができます。Phoenixで一般的に使用されるテンプレートエンジンは```eex```です（[Embedded Elixir](http://elixir-lang.org/docs/stable/eex/)）。すべてのテンプレートファイルの拡張子は```.eex```となっています。

tempalteはViewとControllerのどちらの範囲にも含まれます。実際に即して簡単に言えば```web/template```ディレクトリ内にcontrollerの後半の名前をつけたディレクトリを作成します。Helloページのためには```web/templates```ディレクトリ配下に```hello```ディレクトリを作成し、その中に```index.html.eex```ファイルを作成する必要があります。

ここまで進めたら、```web/templates/hello/index.html.eex```を以下のように作成してください。

```
<div class="jumbotron">
  <h2>Hello World, from Phoenix!</h2>
</div>
```

ここまでで私達はroute, controller, view そしてtemplateを作成してきたので、ブラウザで[http://loclhost:4000/](http://loclhost:4000/)にアクセスすることでPhoenixからの挨拶を見ることができます！（サーバを停止して進めてきた場合は```mix phoenix.server```でタスクを再起動してください）

![Hello from Phoenix](https://www.filepicker.io/api/file/TLBRJ5LBR9mK9Fkcqwea "Hello from Phoenix")

ここで私達がしてきたことで興味深い２、３の発見があります。私達は変更を加えるさいにサーバを止めたり再起動したりする必要がありませんでした。そうです、Phoenixは変更したコードを再読み込みしてくれるのです！また```index.html.eex```はdivタグだけで構成されたファイルでしたが、表示されたページは完全なhtmlとなっていました。indexテンプレートはアプリケーションレイアウト（```web/templates/layout/application.html.eex```）の中に組み込まれて生成されるのです。それを開いてみれば```<%= @inner %>```というようなタグを見つけることができるでしょう。ブラウザにhtmlが送出される前にレイアウトファイルのその場所にtemplateが注入されます。

##もう一つの新たなページ
私達のアプリケーションをもう少し複雑にしてみましょう。これから追加する新しいページではURLの一部を認識し、templateの"messenger"ラベルにcontrollerを経由して値を渡してmessengerが挨拶できるようにします。

先ほどやったように、まずは新しいrouteを作成します。

##Routeの作成（動的なページ）
この例題では```HelloController```を再利用してそこに新たに```show```アクションを追加していきます。routeの最後の行の下に以下のように追加します。

```
scope "/", HelloPhoenix do
  pipe_through :browser # Use the default browser stack.

  get "/", PageController, :index
  get "/hello", HelloController, :index
  get "/hello/:messenger", HelloController, :show
end
```

パスの中に```:messenger```というatomがあることに気がつくでしょう。PhoenixはURLの中の指定された位置にあるどのような値でも取得し、```messenger```キーでその値を指すDict型としてcontrollerに渡します。

例えば、[http://localhost:4000/hello/Frank](http://localhost:4000/hello/Frank)でブラウザからアクセスされた場合、":messagener"の値には"Frank"が設定されます。

##Actionの追加（動的なページ）
私達の新しいrouteに対してリクエストがきた場合、```HelloPhoenix.HelloController```の```show```アクションで処理されます。私達は既に```web/controllers/hello_controller.ex```を持っているので、そのファイルを編集して```show```アクションを追加する必要があります。今回はテンプレートにmessengerを渡すことができるようにアクションにわたってきたパラメータを保持する必要があります。そのためcontrollerに以下のようなshow関数を追加します。

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

ここでも２，３のことに気がつくでしょう。URLの```:messenger```の位置にある値を```messenger```変数に割り当てるためにshow関数に渡されたパラメータをパターンマッチで対応させています。例えば、URLが[http://localhost:4000/hello/Frank](http://localhost:4000/hello/Frank)だった場合、messenger変数には```Frank```が割り当てられます。

showアクションの内部ではmessenger変数の値を```:messenger```をキーとするキーバリューのペアとしてrender関数の第３引数に引き渡しています。

ちなみにDict型のキーは常にString型になることを忘れないようにしてください。

##Templateの作成（動的なページ）
このパズルの最後のピースは新たなtemplateを用意することです。```HelloController```の```show```アクションから呼び出すために```web/templates/hello```ディレクトリの中に```show.html.eex```を作成していきましょう。このtemplateはmessengerの名前を表示する必要があることを除いて、```index.html.eex```テンプレートに驚くほど似ています。

messengerの名前を表示するために、Elixirが実行可能な```<%= %>```で表現される特別なeexタグを使用します。タグの最初のほうにイコール記号のようなものがあることに気がつくでしょう（```<%=```）。これらのタグに囲まれている場所ではちょっとしたElixirのコードが実行され、結果の値がタグと置き換えられます。もしもイコール記号を付け忘れた場合は処理は実行されますが、値はページ上に現れません。

結果的にtemplateは以下のようになります。

```
<div class="jumbotron">
  <h2>Hello World, from <%= @messenger %>!</h2>
</div>
```

messengerは```@messenger```に表示されます。この場合の```@messenger```はモジュールの属性ではありません。これは```Dict.get(assigns, :messanger)を置き換える特別なメタプログラミング構文の一部です。templateを使うことで簡単に見栄えの良い結果となります。

これで終わりです。ブラウザで[http://localhost:4000/hello/Frank](http://localhost:4000/hello/Frank)にアクセスすれば、以下のような見た目になっているはずです。

![Frank Greets us from Phoenix](https://www.filepicker.io/api/file/jTxIw39Sma27wHr6z14g "Frank Greets us from Phoenix")

少し遊んでみてください。/hello/の後になにをおいたとしてもあなたのmessengerがページ上に表示されることでしょう。

[< 前](http://qiita.com/rtbt525/items/d65efc631a1661c2686d) 次 >