node.js Express3.xのViewHelperメソッドでSessionの値を使う。
Express2.xとExpress3.xでは、仕様が大きく変わっているようで、2.xのコードを参考に3.xでコードを書いていると思いがけないところでハマってしまいます。
今回はViewHelperメソッドでSessionの値を使う方法でハマってしまいました。
なお、今回紹介するコード実装したExpressバージョンは 3.4.8 です。
ViewHelperメソッドとは?
まず、ViewHelperメソッドについて簡単に説明します。
本記事ではViewの複数箇所で使われる処理を共通化したメソッド群をViewHelperメソッドとよびます。
具体的には下記のようなコードです。
// View Helper exports.helpers = { link_to: function(name, url){ return '<a href="' + url + '">' + name + '</a>'; }, text_format: function(text){ return text.replace(/ /g, ' ').replace(/\r\n|\n|\r/g, '<br />'); } };
app.jsにてapp.localsメソッドの引数にViewHelperメソッドオブジェクトを渡すとViewからViewHelperメソッドを呼び出せるようになります。
var express = require('express'), routes = require('./routes'), lib = require('./lib'); /* 〜省略〜 */ app.locals(lib.helpers); /* 〜省略〜 */
<!-- 〜省略〜 --> <h2 class="title"> <%- link_to(post.title, '/topics/' + topic_id + '/posts/' + post._id) %> </h2> <div class="detail"><%- text_format(escape(post.detail)) %></div> <!-- 〜省略〜 -->
ViewHelperメソッドでSessionを使って実現したい機能。
今回は、Sessionの値を使って次のような機能を実装します。
1.Sessionの値でユーザがログイン中かどうか判断する。
2.ログイン中の場合はユーザ名とログアウトを表示する。
3.ログイン中ではない場合はログインを表示する。
次のコードはエラーになりますが、実装イメージはこんな感じです。
// View Helper exports.helpers = { link_to: function(name, url){ return '<a href="' + url + '">' + name + '</a>'; }, text_format: function(text){ return text.replace(/ /g, ' ').replace(/\r\n|\n|\r/g, '<br />'); } username_or_login: function() { // このままではsessionは定義されていないためエラーになる。 if(session.username){ return '' + '<p class="login_user">Login as ' + session.username + '</p>' + '<p class="logout"><a href="/sessions/destroy">logout</a></p>'; } return '<p class="login"><a href="/sessions/new">login</a></p>'; } };
ViewHelperメソッドでSessionの値を使う実装。
ViewHelperメソッドでもSessionの値を使えるように修正を加えていきます。
var express = require('express'), routes = require('./routes'), lib = require('./lib'); var viewSession = {}; /* 〜省略〜 */ app.use(express.cookieParser('your secret here')); app.use(express.session()); app.use(function(req, res, next){ // これだとviewSessionにreq.sessionの参照が代入され、 // Viewではreq.sessionが開放されてしまうためエラーになる。 // viewSession = req.session; viewSession.username = req.session.username ? req.session.username : ''; next(); }); /* 〜省略〜 */ app.locals(lib.helpers(viewSession)); /* 〜省略〜 */
exports.helpers = function(session){ return { link_to: function(name, url){ return '<a href="' + url + '">' + name + '</a>'; }, text_format: function(text){ return text.replace(/ /g, ' ').replace(/\r\n|\n|\r/g, '<br />'); }, username_or_login: function() { if(session.username){ return '' + '<p class="login_user">Login as ' + session.username + '</p>' + '<p class="logout"><a href="/sessions/destroy">logout</a></p>'; } return '<p class="login"><a href="/sessions/new">login</a></p>'; } }; };
<!-- 〜省略〜 --> <div> <h1><a href="/">Node Express</a></h1> <div><%- username_or_login() %></div> </div> <!-- 〜省略〜 --> <h2 class="title"> <%- link_to(post.title, '/topics/' + topic_id + '/posts/' + post._id) %> </h2> <div class="detail"><%- text_format(escape(post.detail)) %></div> <!-- 〜省略〜 -->
ちょっと強引かもしれませんがこれでViewでもSessionの値を使うことができます。
2.xではどのように実装するか。
2.xでは req,res を受け取れる app.dynamicHelpers で実現出来ていました。
また、次のサイト app.locals.use を使った方法が紹介されていますが、 app.locals.use は3.xのどこかのバージョンでなくなってしまっています。
A Node in Nodes - 日本最速express3入門
課題
Sessionの値が増える毎にapp.jsを編集しなければならない。
今回紹介した方法では、viewSessionのプロパティにいちいち値を設定しているのでViewHelperメソッドで使いたいSessionの値が増える度にapp.jsの修正が必要になります。
req.sessionオブジェクトをviewSessionにCloneしたいのですが、javascriptでオブジェクトをcloneする標準の方法はないようです。(jQueryにはあるようです。)
javascriptのオブジェクトのcloneについて詳しくは次の記事を参照下さい。
JavaScriptのオブジェクトをコピーする - Hのキーがhellで、Sのキーがslaveだ、と彼は思った。そしてYのキーがyouだ。
最後に
もっとスマートは方法があればコメント頂けると幸いです。
参考図書
- 作者: 清水俊博,大津繁樹,Jxck,小林秀和,佐々木庸平,篠崎祐輔,高木敦也,西山雄也
- 出版社/メーカー: アスキー・メディアワークス
- 発売日: 2012/10/26
- メディア: 大型本
- 購入: 31人 クリック: 803回
- この商品を含むブログ (7件) を見る