Express3.xのViewHelperメソッドでSessionの値を使う。

Express2.xとExpress3.xでは、仕様が大きく変わっているようで、2.xのコードを参考に3.xでコードを書いていると思いがけないところでハマってしまいます。

今回はViewHelperメソッドでSessionの値を使う方法でハマってしまいました。
なお、今回紹介するコード実装したExpressバージョンは 3.4.8 です。

# ViewHelperメソッドとは？
まず、ViewHelperメソッドについて簡単に説明します。
本記事ではViewの複数箇所で使われる処理を共通化したメソッド群をViewHelperメソッドとよびます。
具体的には下記のようなコードです。

```js:lib/sindex.js
// View Helper
exports.helpers = {
	link_to: function(name, url){
		return '<a href="' + url + '">' + name + '</a>';
	},
	text_format: function(text){
		return text.replace(/ /g, '&nbsp').replace(/\r\n|\n|\r/g, '<br />');
	}
};
```

app.jsにてapp.localsメソッドの引数にViewHelperメソッドオブジェクトを渡すとViewからViewHelperメソッドを呼び出せるようになります。

```js:app.js
var express = require('express'),
	routes = require('./routes'),
	lib = require('./lib');
/* 〜省略〜 */
app.locals(lib.helpers);
/* 〜省略〜 */
```

```html:views/topics/show.ejs
<!-- 〜省略〜 -->
<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の値を使って次のような機能を実装します。
１．Sessionの値でユーザがログイン中かどうか判断する。
２．ログイン中の場合はユーザ名とログアウトを表示する。
３．ログイン中ではない場合はログインを表示する。
次のコードはエラーになりますが、実装イメージはこんな感じです。

```js:lib/index.js
// View Helper
exports.helpers = {
	link_to: function(name, url){
		return '<a href="' + url + '">' + name + '</a>';
	},
	text_format: function(text){
		return text.replace(/ /g, '&nbsp').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の値を使えるように修正を加えていきます。

```js:app.js
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));
/* 〜省略〜 */
```

```js:lib/index.js
exports.helpers = function(session){
	return {
		link_to: function(name, url){
			return '<a href="' + url + '">' + name + '</a>';
		},
		text_format: function(text){
			return text.replace(/ /g, '&nbsp').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>';
		}
	};
};
```

```html:views/topics/show.ejs
<!-- 〜省略〜 -->
<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のどこかのバージョンでなくなってしまっています。
http://blog.craftgear.net/4f6fd9c32ea0435951000001/title/%E6%97%A5%E6%9C%AC%E6%9C%80%E9%80%9Fexpress3%E5%85%A5%E9%96%80


# 課題
## Sessionの値が増える毎にapp.jsを編集しなければならない。
今回紹介した方法では、viewSessionのプロパティにいちいち値を設定しているのでViewHelperメソッドで使いたいSessionの値が増える度にapp.jsの修正が必要になります。
req.sessionオブジェクトをviewSessionにCloneしたいのですが、javascriptでオブジェクトをcloneする標準の方法はないようです。(jQueryにはあるようです。)
javascriptのオブジェクトのcloneについて詳しくは次の記事を参照下さい。
http://ledsun.hatenablog.com/entry/20120614/1339641262

# 最後に
もっとスマートは方法があればコメント頂けると幸いです。