タグライブラリの変態っぷりに茶ぁ吹いた(ほめてる)
feedsプラグインを使ってて発見したのだが,まずはこのコントローラのコードを見て欲しい。
def feeds = { render(feedType:"rss", feedVersion:"2.0") { title = "My test feed" link = g.createLink(controller:"blog", absolute: true) Blog.list().each() { blog -> entry(blog.title) { link = g.createLink(controller:"blog", action:"show", id:blog.id, absolute:true) } } } }
注目は「g.createLink()
」。なんぞこれ?と思ってみたが,答えは簡単,GSPのcreateLinkタグだった。
どうやら,GSPのタグライブラリはコントローラからも使えるらしい。そりゃ,どんな裏技だと思いリファレンスひいてみたら,それっぽい記述を発見。
Tags within namespaces can be invoked as methods using the namespace as a prefix to the method call:
out << my.example(name:"foo")This works from GSP, controllers or tag libraries
6.3.5 Tag Namespaces - Grails Framework Reference Document
要するにタグライブラリはGSPやコントローラ内でメソッドとしても利用できるそうだ。JSPのtaglibがFunctionsも兼用しているって感じなんだろう。だから,下記の2つは同じ意味になる。
#標準タグの場合,GSP中ではネームスペース 'g' は省略できるみたい。
<g:createLink action="show" id="1"/> ${createLink(action:"show', id:"1")}
試しにコントローラ内で「println g.class.name
」とかってやると,こんなのが返ってきた(独自タグを作った場合は,g
をそのタグのネームスペースに置き換えると良い)。
org.codehaus.groovy.grails.web.taglib.NamespacedTagDispatcher
だから,コントローラからもユーティリティ的にタグライブラリを利用することができるわけだ。リファレンスに書いてあるくらいだから,当たり前に使って良いんだよね。つか,これ便利すぎるよ,ママン!!:-)
ちょうどJSON形式で複数をHTML片を返したいなって思ったんだが,コントローラのrender(template:〜)じゃ実現できないのに気付いたワケ。だって,これ戻り値無いでしょ。かといって,MarkupBuilderでHTML片作るのもたるくてJSONで返すの諦めてたんだけど,この方法知って,あっという間に解決した。
つまり,こんな風に書けば,複数のテンプレートを束ねることができるのだ。
render([main: g.render(template: "main_tempalte", model: [foo: foo, bar: bar]), sub: g.render(template: "sub_template", model: [hoge:hoge])] as JSON)
↑ちょっとわかりづらいけど,renderタグをメソッドとして利用している(g.render(〜
んとこ)。むろんテンプレの中にはGSPタグを使ってたって構わない。この超便利さ,わかってくれるかしら?
ちなみにサービスではこの方法は使えないので,このリンク先にあるようにGroovyPagesTemplateEngine
を使うらしい。試してないからアレだけど,例えば電子メールのテンプレにGSPを使いたい場合などに使えるようだ。
→ Grails – Rendering a Template from a String | Disgruntled Developers
あと,AcegiSecurityプラグイン使ってんだけど,これもいくつか便利なタグがあるんのね。たとえば,ログインしてる時だけ評価されるような,g:isLoggedIn
タグとか。
<g:isLoggedIn> ログインしてると,ここが表示されるス </g:isLoggedIn>
もちっと器用に「ログインしてて,かつ自分のものだったら評価する」みたいな条件付けも,今回の件で解決した。Acegiにはログインしているユーザ名を出力するg:loggedInUsername
ってタグがあるんで,これを使ってこんな感じにするとできた。
<g:isLoggedIn><g:if test="${loggedInUsername() == account.username}"> ログインしててかつ,accountが自分のモノなら,ここが表示される。 </g:if></g:isLoggedIn>
わはは。融通利きすぎて笑える。Grailsって発想が斜め上を行きすぎてて,もうJSP使えないかも知んない。:-P
#あわせて読みたい。→ うぬはまだEL(式言語)の本当の恐ろしさをしらぬ - しんさんの出張所 はてなブログ編
ps.
どうやらタグライブラリをメソッドとして使った場合,out変数に突っ込んだ内容が戻り値となるようですね。あと当然,タグボディは評価されない。
LogicalタグやIterativeタグがどう評価されるかは試してないけど,無理に試すもんでもないか(必要になったら確認してみる)。
-
-
- -
-
2009.06.20 追記:
ついてる時はどこまでもついているのぅ。
→ groovy - Grails link taglib use outside of GSP - Stack Overflow
タグライブラリをメソッドとして評価した場合,タグボディはキーワード無しパラメタかクロージャで渡せば良いんだそうな。なので,
<g:link controller="foo" action="foo">text of the link</g:link>
は,こんな風に書ける。
g.link(controller:"foo", action:"bar", "text of the link") g.link(controller:"foo", action:"bar") { "text of the link" }
タグライブラリのシグネチャが
def tagname = { attrs, body -> ... }
なので,なるほどと言えばなるほどな答え。