スポンサーリンク

2015年6月2日

Phoenixのコントローラ(Controllers)について分かったこと(その1)

タイトル: Phoenixのコントローラ(Controllers)について分かったこと(その1)


目的: Phoenixアプリケーションのコントローラ(Controllers)について分かったことを記述する。


実施環境:

OS: Windows8.1
Erlang: Eshell V6.4
Elixir: v1.0.4
Phoenix Framework: v0.13.1
Node.js: v0.12.4

目次:


  1. 概要
  2. Controllerの基本的なこと
  3. Actionの基本的なこと
  4. Flash Messagesの使い方
  5. Renderingに関してあれやこれや
  6. おまけ


1.概要


1.1

Phoenix - Guides Controllersの原文が長いよ!
内容的に二分割しないと長くなりすぎるので二回記事上げる。

注意!!
この記事は、Phoenix - Guides ControllersをGoogle翻訳を使い、分かったことを書いています。
原文を丸々翻訳しているわけではないので、
流れや説明がおかしいところ多々ありますが、その点注意して下さい。

英語が分かる方は、公式ガイドを見た方が確実です。

また、管理人の英語力は本人がドン引きするほど低いので、
間違った解釈及び理解している部分が多分にあると思います。

それでも構わないという方は見て頂けたら嬉しいです。

また、ご指摘等があれば受け付けておりますゆえ、遠慮なくお願いします。
特に間違えて習得している部分は教えて頂ければ、本当に助かります。

1.2

あらかじめ、テスト用のプロジェクトは作成しておいて下さい。

2.Controllerの基本的なこと


2.1

Phoenix Controllersは、中間モジュール。

動作順番
1: HTTP要求
2: ルータ
3: コントローラ
4: アクション
5: ビュー層呼び出しまたは、JSONレスポンスを返す

大概、Plugで何とかなるらしいこと書いてた。
でも、Plugの記事分からない。

2.2

コントローラの置き場所
場所: アプリケーション名/web/controllers/

アプリケーションを新規で作成すると以下が生成される。
デフォルトのコントローラ: アプリケーション名/web/controllers/page_controller.ex

デフォルトのPageControllerを例にプログラム内容を説明する。
以下の記述で、モジュールをインポートしている。
use HelloPhoenix.Web, :controller

Phoenix.Controller.Pipelineモジュールで定義されたプラグのマクロ。
plug :action
(plug :renderとかある・・・後ろの項目でやる)

indexアクションがデフォルトで記述されている。(router.exでルーティング先を定義している)
def index(conn, _params) do
  render conn, "index.html"
end

3.Actionの基本的なこと


3.1

アクション名は好きな名前を付けられる。
アクション名はrouter.exに定義されたルートと一致していること。

しかし、アクション名には可能な限り従うべき規則がある。
  • index: 特定のリソースタイプにおけるアイテムを全てレンダリングする
  • show: IDで個々の項目を描画する
  • new: 新しいアイテムを作成する時にフォームをレンダリングする
  • create: 新しい項目のため、paramsを受信してデータストアに保存する
  • edit: IDで検索し、個々の項目を編集するためのフォームを表示する
  • update: 編集項目のためのparamsを受信して、データストアに保存する
  • delete: 削除するアイテムのIDを受信し、データストアから削除する

3.2

実際にPageControllerのアクション名を変更してみる。

3.3

まず、web/router.exを開きscopeの以下の部分を修正する。

修正前: get "/", HelloPhoenix.PageController, :index
修正後: get "/", HelloPhoenix.PageController, :test

3.4

web/controllers/page_controller.exを開きアクション名をtestに修正する。
----
def test(conn, _params) do
  render conn, "index.html"
end
----

3.5

以下のコマンド実行する。
コマンド: mix phoenix.server

3.6

以下のアドレスへアクセスする。
アドレス: http://localhost:4000

修正前と動作が変わらないことを確認する。
(エラーが出なければそれでいい)

3.7

testに修正した部分を元のindexに直しておいて下さい。

4.Flash Messagesの使い方


4.1

アクション中にユーザと通信する必要がある。
例えば、モデルの更新中にエラーが発生したり・・・
アプリケーションでそれらを受け入れたい。
そのため、Flash Messangesがある。

4.2

何はともあれ、とりあえず使ってみる。

web/controllers/page_controller.exを開いてindexアクションを以下のように修正する。
----
def index(conn, _params) do
  conn
  |> put_flash(:info, "Welcome to Phoenix, from flash info!")
  |> put_flash(:error, "Let's pretend we have an error.")
  |> render "index.html"
end
----

"|>"はメソッドチェーンですね。
詳しくはElixirのドキュメント見ると参考になります。

4.3

web/templates/layout/application.html.eexを開いて以下の記述を確認する。
(既に記述がある)
----
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
----

4.4

以下のコマンド実行する。
コマンド: mix phoenix.server

リロードあるから起動しっぱなしでもいけるけど・・・

4.5

以下のアドレスへアクセスする。
アドレス: http://localhost:4000

ページ開いてエラーが出た方、3.7にある通り、testから直しましょう。
私は忘れていました。(router.exで)エラーが出た・・・

4.6

把握しているFlash Messagesを簡単に説明する。

put_flash: KeyとValueのペアとして設定
get_flash: KeyとValueのペアとして取得
persist: 現在の要求サイクルを超え、ValueをFlash Messagesとしてセッションに保存できる。
clear_flash: セッションに格納されているであろうFlash Messagesを削除する。

5.Renderingに関してあれやこれや


5.1

renderでレンダリングすることができる。
レイアウトにテンプレートがレンダリングされる。

それ以外にも、text、json、htmlで出力することができる。

5.2

実際にそれぞれの出力を試してみよう。
web/router.exを開きscopeに以下の記述を追加する。
追加: get "/:id", PageController, :show

5.3

web/controllers/page_controller.exを開き、
一つずつ修正しながら試して下さい。

5.4

text: プレーンテキストを出力
----
def show(conn, %{"id" => id}) do
  text conn, "Showing id #{id}"
end
----

5.5

json: jsonブロックを出力
----
def show(conn, %{"id" => id}) do
  json conn, %{id: id}
end
----

5.6

html: アクションに直接記述することで、テンプレートなしでレンダリングできる。
----
def show(conn, %{"id" => id}) do
  html conn, """
     <html>
       <head>
          <title>Passing an Id</title>
       </head>
       <body>
         <p>You sent in id #{id}</p>
       </body>
     </html>
    """
end
----

5.7

実行してそれぞれの出力結果、表示結果を確認する。
実行方法はここから以下省略する。

5.8

get "/:id", PageController, :showの記述とshowアクションは消しておいて下さい。

5.9

renderプラグのショートカットを使う。

web/controllers/page_controller.exを開き、
renderプラグの追加とindexアクションを以下のように修正する。
----
defmodule HelloPhoenix.PageController do
  use HelloPhoenix.Web, :controller

  plug :action
  plug :render

  def index(conn, _params) do
    conn
  end
end
----

renderを省略できる。

"index.html"の記述がないですが、
内部で自動的にアクション名からテンプレートを選択しているようです。
showアクションで"index.html"を指定していましたが、
renderを省略して記述すると"show.html"のテンプレートがねぇよと実行時エラーが出ます。

5.10

renderプラグを特定のアクションのみで適応して欲しいときの書き方。
一部のアクションではjsonを返したい等と言った時に使うとのこと・・・
例) plug :render when action in [:index, :show]

6.おまけ


6.1

Gathering Data(直訳: データ収集)
Phoenixには独自のデータアクセス層はない。
ただしElixirプロジェクトで、とても良いPostgresのソリューションを提供をしているとのこと。

他のデータアクセスオプションはあるみたい。
ETSとDETSは、OTPに内蔵されているKey値データを格納している。
OTPまたはQLCと呼ばれる独自のクエリ言語とmnesiaと呼ばれるRDBを提供している。

DBは重要であるが、ガイドでこれらのオプションをカバーしません・・・っと・・・まじか!?

(ここら辺よく分からない・・・故におまけ)

6.2

connとparams
conn: ホスト、パス要素、ポート、クエリ文字列などの要求に関する情報を保持する構造体。
(connはPlugに詳細が載っている・・・Plugやるしかないのね・・・)

params: HTTPリクエストのパラメータを保持してるMap

paramsの参考としては、
Phoenix - Guides Adding Pagesでメッセンジャーパラメータを渡した項目。
私は、正直あれで理解はできなかったけど・・・

一応、参考までに書いた記事も・・・

6.3

レンダリングするために、コントローラ以外のものについてまとめ。
PageControllerには、PageViewが必要。
PageViewには、index.html.eexテンプレートが含まれているpageディレクトリが必要。

6.4

@messageや@nameと言った形でテンプレートにて利用したい場合。

単一の渡し方
----
def index(conn, _params) do
  assign(conn, :message, "Welcome Back!")
end
----

複数の渡し方
----
def index(conn, _params) do
  conn
  |> assign(:message, "Welcome Back!")
  |> assign(:name, "Dweezil")
end
----

私の場合以下のようなタグを記述し出力させてみた。
web/templates/page/index.html.eexのテンプレートファイルへ以下のような行を追加した。
<p><%= @message %></p>
<p><%= @name %></p>

メモ1: 渡してないものを使おうとすると実行時エラーになる(空白では表示されない)
メモ2: render plugがないとレンダリングされない(画面真っ白)。

6.5

HTTPのステータスを通知する方法。
----
def index(conn, _params) do
  conn
  |> send_resp(201, "")
end
----

空白のページが表示される。
HTTP Headerを確認するとステータス201になっている。

コンテンツの種類を具体的にしたい時は、以下のようにする。(どうゆうこと?)
空白のページが表示される。
----
def index(conn, _params) do
  conn
  |> put_resp_content_type("text/plain")
  |> send_resp(201, "")
end
----

なんか、send_resp(201, "")を投げるとエラーが出るんだよな・・・なんでだろう・・・
解決した・・・plug :renderをコメントアウトしたら。

以上!!その2へ続く~

以下、参考とさせて頂いたサイト様

管理人の独り言~
長い、長いよ~。

実施手順が、
1: 英語に目を通す
2: Google翻訳
3: 翻訳確認
4: ソースコードあれば実行

っといったサイクルで実施しているから進行がひたすら遅い・・・
大分昔のパソコンで最新の技術動かそうとしてなかなか実行に辿り着かないくらい遅い。

と言うわけで、Controllersその1です。

人気の投稿