LoginSignup
8
8

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-06-13

全体へのリンクは以下
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 RunningPhoenix 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

さしあたり、ここではpipelinescopeの使い方は無視してrouteの追加に焦点を当てます(もしもそれらについて気になるようであればRouting Guideでそのトッピクスを説明しています)

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

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

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

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, :controllerplug :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.htmlindex.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でタスクを再起動してください)

Hello from Phoenix

ここで私達がしてきたことで興味深い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.HelloControllershowアクションで処理されます。私達は既に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を用意することです。HelloControllershowアクションから呼び出すために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にアクセスすれば、以下のような見た目になっているはずです。

Frank Greets us from Phoenix

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

< 前 次 >

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8