Golang/Revel: なんでも受けるアクションとビューを作る

Revel で、どのパスにアクセスされても同じコントローラで対応する方法を試す。

ルーティング、アクション、ビュー

Revel で新しいアクションとビューを作る場合、どんなリクエストがあったときにどのアクションを呼び出すかという関連付けも行う必要がある。この関連付けをルーティングと呼ぶ。
どういう順番でやるのがあるべき姿なのかわからないので、とりあえずアクションから行こう。

アクション

作成したディレクトリの app ディレクトリ配下にソースが格納されている。controllers/app.go がテンプレートで作られたコントローラ。すでに Index というアクションが定義されているが、とりあえずこれをコピって View という名前で作ってみる。アクションの名前が View というのはややこしくなりそうだが、View (表示) というアクションを作りたいのでこの際やむを得ない。

func (c App) View(path string) revel.Result {
	head := "<h1>" + path + "</h1>"
	return c.Render(head)
}

恥ずかしながら Golang 初心者なので細かい部分がよくわかっていないが、追い追いわかるようになるだろう。たぶん。

ビュー

app/views/App の下に、ビューごとの HTML テンプレートがある。
テンプレートからプロジェクトを作った時点で、Index.html がある。今回はそれと同じ場所に View.html を作る。

{{.head}}

これまたよくわかっていないが、どうやら {{ }} の中に . と呼び元の変数名を書けばいいらしい。

ルーティング

conf/routes というファイルがルーティングの定義。GET で / が要求された時は App の Index 関数を呼ぶ、というようなことが書かれている。
1 行で 1 つの条件と対応するアクションを書いていくが、リクエストがこのファイル内の複数の条件に合致した場合、上にあるものが使われる。ということで、今回はファイルの一番下に以下の内容を追加する。

GET     /*path                                  App.View

パスのうち *path は、任意の文字列を表し、これを第 1 引数として渡す、という意味。* の代わりに : を書くと、/ を含まない文字列、つまりパスの 1 レベル分だけ、ということになる。
そしてもうひとつ、すぐ上に

*       /:controller/:action                    :controller.:action

という行がある。/App/View にアクセスされたら App.View を呼ぶ、というような汎用のマッピングっぽいが、今回は邪魔なのでコメントアウトして

#*       /:controller/:action                    :controller.:action

としておく。

エスケープの抑止

さて、さっそくアプリを動かしてみよう。
http://localhost:9000 にアクセスすると元からある index のアクションが動いてしまうので、ブラウザのアドレスバーに http://localhost:9000/foo とか http://localhost:9000/foo/bar とか入れてみる。
……すると、ブラウザ上に

<h1>foo</h1>

とか

<h1>foo/bar</h1>

とかが表示されてしまった。うん、たぶんそうなるんじゃないかなと思ってた。
HTML を渡したつもりなのに、フレームワークがうまいことエスケープしてくれてしまった結果、見出しが表示されずにタグがそのままブラウザ上に表示されてしまったわけだ。
公式サイトの下記のページに解決法がある。

つまり、ビューを以下のように直せばよい。

{{raw .head}}

もう一度アクセスすると、ちゃんと foo や foo/bar が見出しとして表示される。