JavaScript URLMapper
ちょっと複雑なパス体系を持つRailsアプリでJSONでAJAXする人には役に立つかもしれない。 GoogleMapsとかね。
要 prototype.js
使い方はこんな風。
URLMapper.connect(
"/user/:user_id/category/:category_id/entry/:action/:entry_id",
{controller: 'entry', action: 'index', entry_id: null});
URLMapper.connect(
"/user/:user_id/category/:action/:category_id",
{controller: 'category', action: 'index', category_id: null});
URLMapper.connect(
"/user/:action/:user_id",
{controller: 'user', action: 'index', user_id: null});
URLMapper.connect(
"/:controller/:action/:id",
{action: 'index', id: null});
URLMapper.url_for({controller: 'entry'});
// -> "/entry/index/"
URLMapper.url_for({controller: 'entry', action: 'new'});
// -> "/entry/new/"
URLMapper.url_for({controller: 'category', action: 'new'});
// -> "/category/new/"
URLMapper.url_for({controller: 'category', action: 'new', user_id: 3});
// -> "/user/3/category/new/"
URLMapper.url_for({controller: 'category', action: 'update', user_id: 3, category_id: 2});
// -> "/user/3/category/update/2"
URLMapper.url_for({controller: 'entry', action: 'update', user_id: 3, category_id: 2, entry_id: 1});
// -> "/user/3/category/2/entry/update/1"url_for は可変長引数をとって、引数をHashとしてマージするので、
//サーバからJSONを取得。
//[{user_id: 3, category_id: 2, entry_id: 1}, ...]
var entries = getJSON();
URLMapper.url_for({controller: 'entry', action: 'update'}, entries[0]);
// -> "/user/3/category/2/entry/update/1"とか。
ソースはこんなの。
Hash.prototype.subtract = function(op2) {
var result = $H().merge(this);
this.remove.apply(result, $H(op2).keys());
return result;
};
var URLMapper = {
url_options: $A(),
UrlOption: function(url, required, defaults, match) {
this.url = url.gsub(/\/:([A-z_][A-z0-9_]*)/, function(match) {return '/#{' + match[1] + '}'});
this.required = required;
this.defaults = defaults;
this.match = match;
},
extractParameters: function(url) {
var params = $H();
url.scan(/\/:([A-z_][A-z0-9_]*)/, function(match) {params[match[1]] = true});
return params;
},
connect: function(url, defaults) {
url = url.gsub(/%3A/, ':');
var params = this.extractParameters(url);
var required = params.subtract(defaults);
this.url_options.push(new this.UrlOption(url, required, $H(defaults), $H(defaults).subtract(params)));
},
url_for: function() {
var options = $A(arguments).inject($H(), function(r, v){return r.merge(v)});
var detected = this.url_options.select(
function(url_option) {
return url_option.required.subtract(options).size() == 0 && url_option.match.all(function(pair){return options[pair.key] == pair.value});
}
).sortBy(function(url_option) {
return $H(options).subtract(url_option.required).subtract(url_option.defaults).size();
}).first();
if (!detected) {
throw "no URL matches.";
}
return (new Template(detected.url)).evaluate($H().merge(detected.defaults).merge(options));
}
}Tue, 13 Feb 2007 15:03 カテゴリ tech, web, javascript
タグ javascript, json, rails