全体へのリンクは以下
Phoenix Framework Guide をなんとなく訳してみた① Overview
--
#ページの追加
ここではPhoenixアプリケーションに2つのページを追加します。ひとつは単なる静的なページ、もうひとつは入力された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(Phoenix Framework Guide をなんとなく訳してみた② Up And Running)で以前見た"Welcome"ページのRouteは以下のようになっています。
get "/", PageController, :index
このrouteが何を意味するのか整理してみましょう。
http://localhost:4000/でアクセスすると、ルートパスに対してHTTPのGETリクエストが発行されます。その際、すべてのリクエストはweb/controllers/page_controller.ex
に定義されたHelloPhoenix.PageController
モジュールのindex関数で取り扱いますということを意味しています。
このガイドではブラウザから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でそのトッピクスを説明しています)
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まで保留にしておきます。index/2
アクションに注目してください。
コントローラのアクションはすべて2つの引数を取ります。一つ目はconn
でリクエストについての大量のデータを保持する構造体です。2つ目の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)。すべてのテンプレートファイルの拡張子は.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/にアクセスすることでPhoenixからの挨拶を見ることができます!(サーバを停止して進めてきた場合はmix phoenix.server
でタスクを再起動してください)
ここで私達がしてきたことで興味深い2、3の発見があります。私達は変更を加えるさいにサーバを止めたり再起動したりする必要がありませんでした。そうです、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でブラウザからアクセスされた場合、":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
ここでも2,3のことに気がつくでしょう。URLの:messenger
の位置にある値をmessenger
変数に割り当てるためにshow関数に渡されたパラメータをパターンマッチで対応させています。例えば、URLがhttp://localhost:4000/hello/Frankだった場合、messenger変数にはFrank
が割り当てられます。
showアクションの内部ではmessenger変数の値を:messenger
をキーとするキーバリューのペアとしてrender関数の第3引数に引き渡しています。
ちなみに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にアクセスすれば、以下のような見た目になっているはずです。
少し遊んでみてください。/hello/の後になにをおいたとしてもあなたのmessengerがページ上に表示されることでしょう。
[< 前](http://qiita.com/rtbt525/items/d65efc631a1661c2686d) 次 >