LoginSignup
3
1

More than 5 years have passed since last update.

Phoenixを触ってみる その5

Posted at

前回 またいつかと言っていたPlugの話です。

Plug

Plugは、Webアプリケーション間で構成可能なモジュールの仕様です。

…とりあえずgoogle翻訳してみましたけど、良くわかりませんね。

とりあえずこんな理解をしておけば良さそうかと思ってます。

  • Plug.Connという構造体を通じて処理を行う仕組み
  • Plug.Connを受け取ってPlug.Connを返すという仕組みに則り、処理を組み合わせることが出来る
  • plug HogePlug と書くことで順に実行される

仕組み的な話はいったん置いておきます。
…メタプログラミング勉強しないと。

Function Plug

関数によるPlug。
これまでの例ではRouterに plug HogePlug を書いてたけど、Controllerにも書けます。

Controllerに書くことで、Controller内での共通処理のようなものが実装できるようです。

hello_controller.ex
defmodule HelloWeb.HelloController do
  use HelloWeb, :controller

  plug :checkAdmin

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

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

  defp checkAdmin(%Plug.Conn{params: %{"messenger" => "admin"}} = conn, _) do
    render conn, "admin.html", messenger: "admin"
  end

  defp checkAdmin(conn, _) do
    conn
  end
end

この場合、index,showどちらへのアクセスであっても、
パラメータ"messenger"がadminであればadmin.htmlを表示します。

ガイドの方にもあるようにヘッダ追加したりとかってときに使うようですね。

Module Plug

関数ではなく、モジュールとして定義されたPlug。
実際に使われるときの挙動は同じで、定義の仕方が違うだけです。

実装すべき関数は2つ

  • init/1 引数はplug利用時に渡す。
  • call/2 第1引数はPlug.Conn、第2引数はinit/1の返り値。Plug.Connを返します。

call/2に関してはFunctionPlugで作った関数と同じですね。
使い方はFunctionPlugとほぼ同じで、atomの代わりにモジュール自体を渡します。

hello_controller.ex
defmodule HelloWeb.MyPlug do
  import Plug.Conn

  def init(initOption) do
    initOption #これがcall/2の第2引数に渡る
  end

  def call(%Plug.Conn{params: %{"messenger" => "utonton"}} = conn, ops) do
    assign(conn, :hoge, "様") #Plug.Connの関数。値を引き回したいときに使うっぽい
  end

  def call(conn, ops) do
    assign(conn, :hoge, ops)
  end
end

defmodule HelloWeb.HelloController do
  use HelloWeb, :controller

  plug HelloWeb.MyPlug, "さん" #この"さん"がinit/1に渡る

  def show(conn, %{"messenger" => messenger}) when messenger=="utonton" do
    render conn, "special.html", messenger: messenger <> conn.assigns[:hoge]
  end

  def show(conn, %{"messenger" => messenger}) do
    render conn, "show.html", messenger: messenger <> conn.assigns[:hoge]
  end
end

それぞれの関数でどのように値が流れていくのかが分かるかと思います
※内容がPlugでやるようなことではないのは気にしないでください。

モジュールにすることで複数のControllerやRouterに適用することが出来るようになるのがメリットですかね。
基本的にはこっちでの実装がメインになる気がしています。


Plug自体はPhoenix独自のものではなく、elixirのものです。
そして、PhoenixのほとんどはPlugで出来ています。
一見RouterやEndpointなど色々な登場人物が出てくるPhoenixですが、実は全て同じ仕組み上にあると考えると、面白いですね。

ただ実装時には、どこでPlugを差し込むべきかは考える必要がありそうです。
RouterかControllerか、ある程度ルールを設けないとカオスが見えてきそう。

3
1
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
3
1