はじめに
前回、mix phoenix.new
で作ったアプリケーションのパスを覗いてみました。
今回は、Phoenix公式ページのAdding Pagesを見ながら、ページを追加していきます。
なお、次回はガイドラインのRoutingです。
追加している書物
New Route
初期状態で、ルーティングを設定するファイルはweb/router.ex
にあります。
このファイルでは、HTTPメソッドとパスを、ControllerとActionにマッピングすることでルーティングを表します。
前回のデフォルトページの例だと以下のようになります。
get "/", PageController, :index
これは、GETメソッドでルート(/)パスへアクセスを、HelloPhoenix.PageController(web/controllers/page_controller.ex
)のindexにマッピングしていることを表します。
では、/helloへのGETアクセスを、HelloPhoenix.HelloControllerのindexにマッピングしてみます。
web/router.ex
のscopeに、get "/hello", HelloController, :index
を追加します。
scopeやpipelineについては、ひとまずおいておきます。
scope "/", HelloPhoenix do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
get "/hello", HelloController, :index
end
New Controller
Phoenixで言うControllerとはElixirのモジュールであり、ActionはElixirの関数です。
したがって、前項で追加したルーティングのControllerとActionは次のようになります(web/controllers/hello_controller.ex
)。
defmodule HelloPhoenix.HelloController do
use HelloPhoenix.Web, :controller
def index(conn, _params) do
render conn, "index.html"
end
end
index/2
関数の最初の引数conn
は、リクエストに関するさまざまな情報が含まれています。
二つ目の引数_params
は、リクエストパラメータが格納されます。今回は参照しないので、先頭に"_"を付けておきます。
このアクションの中身render conn, "index.html"
は、テンプレートindex.html.eex
を探してレンダリングすることを表しています。
このファイルは、テンプレートディレクトリの後にコントローラの名前を追加したディレクトリ(web/templates/hello/
)から探されます。
なお、render conn, :index
とアトムを使うこともできますが、この場合は、acceptヘッダ応じてindex.htmlやindex.jsonなどのテンプレートが選択されます。
New View
PhoenixではレンダリングはViewの仕事です。
Viewでは、Controllerからレンダリングに必要なデータを受け取り、表示用に変換し、テンプレートに適用して表示するといった作業を行います。
前述作成したHelloControllerに対してはHelloViewを用意する必要があります。なお、Viewの前の名前(Hello)は、Controllerと一致しておく必要があります。
HelloViewは、web/views/hello_view.ex
に以下のように作成することにします。
defmodule HelloPhoenix.HelloView do
use HelloPhoenix.Web, :view
end
New Template
Phoenixでは、標準のテンプレートとしてEExを使用します。
Templateは、テンプレートディレクトリ(web/templates/
)に後にControllerの名前(hello)を追加したディレクトリ(web/templates/hello
)に配置します。テンプレート名はControllerで定義(index.html)したファイルに拡張し(.eex)を追加したファイルになります(web/templates/hello/index.html.eex
)。
<div class="jumbotron">
<h2>Hello World, from Phoenix!</h2>
</div>
Phoenixサーバを起動(mix phoenix.server
)して、ブラウザでlocalhost:4000/hello
にアクセスしてみます。なお、Phoenixサーバを起動しっぱなしだった場合でも、再起動する必要はありません。アクセスされたときに必要であれば再ビルドされます。
index.html.eexにはdivしかありません。html本体はweb/templates/layout/app.html.eex
にあり、このファイル内の以下の部分にindex.html.eexの内容が差し込まれます。
<main role="main">
<%= render @view_module, @view_template, assigns %>
</main>
もう一つアクション
もう一つ、URLの一部に"messenger"という名前を付けて、パラメータとしてControllerに渡して、そのパラメータを含むページを表示する例を作成します。
New Route2
Routeにパラメータを表すアトム":messenger"を追加した行を追加します。
URLでアトムに対応する部分がパラメータとしてControllerに渡されます。
例えば、以下のRouteに対してlocalhost:4000/hello/Hogehoge
を与えると、パラメータ"messenger"に"hogehoge"が割り当てられます。
scope "/", HelloPhoenix do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
get "/hello", HelloController, :index
get "/hello/:messenger", HelloController, :show
end
New Action2
web/controllers/hello_controller.ex
はすでに作成済みですので、これにshow Actionを追加します(:showは前項でRouteに追加したAction)。
show関数の第二引数はパターンマッチングで実装しています。
def show(conn, %{"messenger" => messenger}) do
render conn, "show.html", messenger: messenger
end
Controllerのrender/3は、第三引数にパラメータを渡すことができ、そのパラメータはViewに渡されます。
New Template2
show Actionに対応するTemplate(web/templates/hello/show.html.eex
)を作成します。
EExには、<%= %>
内にElixirの式を書くことができます。
なお、@messenger
は、テンプレートで使用できるメタプログラミングな書き方で、Dict.get(assigns, :messenger)
と同じ意味です。これによりシンプルにパラメータを表現することができます。
<div class="jumbotron">
<h2>Hello World, from <%= @messenger %>!</h2>
</div>
これでlocalhost:4000/hello/hogehoge
などとアクセスすると、"Hello World, from hogehoge!"とブラウザに表示されることになります。