Ember.Router in its current version does not provide means to handle unknown routes. Time to hack!
Solution 1 - Quick and dirty
The idea here is the following. We have the Ember.Router.route(path)
method, which is invoked with the requested (potentially unknown) path. After the invocation of this method, the path of the router is guaranteed to be known. So, if we compare the requested path and the actual path and they differ - then the requested path is invalid and we may redirect a user to the 404 page.
App.Router = Ember.Router.extend({
route: function(path) {
this._super(path);
var actualPath = this.get("currentState").absoluteRoute(this);
if (path !== actualPath) {
this.transitionTo("404page");
}
}
});
This solution is quite expensive. For example, if the current state is "/a/b/c", and a user wants to navigate to "/b/d/e/unknown", the router will dutifully enter known states "b", "d" and "e", and only then we discard the path as unknown. It would be nice if we can tell this before the actual routing starts.
Solution 2 - Fiddling with private methods
Here we check the validity of the given path, and only then tell the router to proceed:
App.Router = Ember.Router.extend({
checkPath: function (path) {
path = path.replace(this.get('rootURL'), '').replace(/^(?=[^\/])/, "/");
var resolvedStates = this.get("states.root").resolvePath(this, path);
var lastState = resolvedStates.get("lastObject");
return lastState.match.remaining == "";
},
route: function(path) {
if (this.checkPath(path)) {
this._super(path);
} else {
this.transitionTo("404page");
}
}
});
This solution also has its drawback - it uses the resolvePath
method which is marked as private. Nevertheless, I'd use this solution, since it is more effective than the first one.