前回 またいつかと言っていたPlugの話です。
Plug
Plugは、Webアプリケーション間で構成可能なモジュールの仕様です。
…とりあえずgoogle翻訳してみましたけど、良くわかりませんね。
とりあえずこんな理解をしておけば良さそうかと思ってます。
- Plug.Connという構造体を通じて処理を行う仕組み
- Plug.Connを受け取ってPlug.Connを返すという仕組みに則り、処理を組み合わせることが出来る
-
plug HogePlug
と書くことで順に実行される
仕組み的な話はいったん置いておきます。
…メタプログラミング勉強しないと。
Function Plug
関数によるPlug。
これまでの例ではRouterに plug HogePlug
を書いてたけど、Controllerにも書けます。
Controllerに書くことで、Controller内での共通処理のようなものが実装できるようです。
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の代わりにモジュール自体を渡します。
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か、ある程度ルールを設けないとカオスが見えてきそう。