Redirect in Ember Router - ember.js

I have a situation where we used to have a login page but now we use a separate oAuth page. I'm trying to clean out a bunch of code, but I need to worry about people who have bookmarked the login route. Ideally, I'd like to be able to do something like this:
Router.map(function () {
this.route('login', {redirectTo: 'index'});
})
and then be able to get rid of the logic in my loginRoute:
var LoginRoute = Ember.Route.extend({
beforeModel: function (transition) {
var result = this._super(transition);
if (transition.isActive === false) {
// Route canceled for auth
return result;
} else {
return this.transitionTo('index');
}
}
});
Is that possible or do I absolutely have to keep my login route?

You can use ember-redirect addon which lets you do what you want:
let Router = Ember.Router.extend({
location: config.locationType,
redirects: {
login: 'index'
}
});

Related

Ember data side loading with JSONAPI

The request generated for my route is http://api.myApp.com/tags/123/products, but I need to do some side loading to improve performance, the desired XHR would be:
http://api.myApp.com/tags/123/products?include=sideload1,sideload2,sideload3
My router looks like this:
this.route('tags', function() {
this.route('tag', { path: ':id' }, function() {
this.route('products', function() {
});
});
});
I'll like to sideload some async models for products, currently I have:
// app/routes/tags/tag/products.js
model() {
return this.modelFor('tags.tag').get('products');
}
How would I go about adding query params in route?
I'm doing something similar in a project and store.query(type, { query }); has worked for me. http://emberjs.com/blog/2015/06/18/ember-data-1-13-released.html#toc_query-and-queryrecord
Try doing a store.query when defining your model and passing in
{include: "sideload1,sideload2,sideload3"}
Another option could be creating an adapter for your model and using buildURL to add on the query params... However this is a bit hacky and shouldn't be necessary if your API is following the JSON API standards.
App.TagsAdapter = DS.JSONAPIAdapter.extend({
buildURL: function(type, id) {
var baseURL = 'http://api.myApp.com/tags/123/products';
var method = '?include=sideload1,sideload2,sideload3';
return baseURL + method;
}
});

Emberjs call a method from an other object

This might be a silly question, but I can't find out anything about it anywhere...
I create a method in one of my controller to verify if the user session is still good, and I'm using this method in almost every page of my app in my beforeModel. But the thing is that I don't want to copy/paste the code every time in every route, this will be dirty and I really don't like it.
Lets say I have this controller :
App.LoginController = Ember.ObjectController.extend({
...
isSession: function() {
var session = this;
Ember.$
.get(host + '/session', function(data) {
console.log('DEBUG: Session OK');
})
.fail(function() {
console.log('DEBUG: Session FAIL');
session.transitionToRoute('login');
});
}
});
How can I call it in this router :
App.HomeRoute = Ember.Route.extend({
beforeModel: function(transition) {
//Here
},
model: function() {
return this.store.all('login');
}
});
I've tried this this.get('loginController').isSession(); but I receive this error Error while loading route: TypeError: Cannot call method 'isSession' of undefined
Thanks for the help !
[edit]
I don't have much to show but this :
My map
App.Router.map(function() {
this.route('login', { path: '/' });
this.route('home');
this.resource('enquiries', function() {
this.route('enquiry', { path: '/:enquiry_id' }, function() {
this.route('update');
});
});
});
Most likely I only Have a LoginController and my HomeRoute. (its the beginning of the app)
I don't need to create a Route for my Login because I have an action helper in my login template and I'm redirected to my Home template after that.
You need to use controllerFor() method in order to call method on controller from router. If method is an action you need to use send() method, like this.controllerFor('login').send('isSession')
App.HomeRoute = Ember.Route.extend({
actions: {
willTransition: function(transition) {
transition.abort();
this.controllerFor('login').isSession()
}
});
If you don't need a return value from isSession you might consider making it an action on a top-level route. The router.send method in the docs has a pretty good example of how you declare actions as well as how you call them. Note that send is also a method you can call on a controller. Actions bubble up from a controller, to the parent route, and then all the way up the route hierarchy, as shown here

Reload current route's model without Ember Data

Ember Data has a reload method; I'm using a more basic approach (using Ember objects) to serve up my models, though.
I'd like a user to be able to reload the model for the current route via an action when e.g. a button is clicked. Is this possible without Ember Data?
Here is a really simple example of how I do it w/ your approach (notice the "clear").
You could invoke clear+find from your route / controller / whatever. I've also added a "beforeSend" to the $.ajax in some of my bigger apps (this will invoke the clear for you before the xhr is resolved)
App.Person.reopenClass({
people: Ember.A([]),
clear: function() {
this.people = Ember.A([]);
},
add: function(hash) {
var person = App.Person.create(hash);
this.people.pushObject(person);
},
remove: function(person) {
this.people.removeObject(person);
},
find: function() {
var self = this;
$.getJSON('/api/people', function(response) {
response.forEach(function(hash) {
var person = App.Person.create(hash);
Ember.run(self.people, self.people.pushObject, person);
});
}, this);
return this.people;
}
});
The issue was the async nature of the AJAX call I was making.
This didn't work:
this.set('model', App.MyObject.findAll(value));
I needed to allow the AJAX call to return the response, then populate the model:
var that = this;
App.MyObject.findAll(value).then(function(response) {
that.set('model', response);
});

Ember RC7: Testing Routes

I would like to test the route setup in my app.
I'm using Qunit and the ember-testing helpers.
I have a test like the following:
test("visit can handle wrong urls", function() {
var urlToVisit = "/foo/bogus";
visit(urlToVisit).then(function () {
// this will show me /foo/bogus even though the route does not exist
console.log(app.__container__.lookup('router:main').location.path);
});
});
The problem is, I can't distinguish between a failed and a successful visit.
Any ideas?
I'm not a QUnit expert but I guess one approach you could take is to test for the currentPath instead of the URL, you can get it from the ApplicationController, something like this:
This test should pass
test("visit 'index' and assert it exists", function() {
var urlToVisit = "/";
visit(urlToVisit).then(function () {
equal(App.__container__.lookup('controller:application').get('currentPath'), 'index', 'At route index');
});
});
But this should fail
test("visit wrong URL and fail", function() {
var urlToVisit = "/posts";
visit(urlToVisit).then(function () {
equal(App.__container__.lookup('controller:application').get('currentPath'), 'posts', 'Fail at non existent route posts');
});
});
Simple demo here.
Hope it helps.

ember.js authentication

I would like to implement authentication with ember.js.
So, when the application start, before the Router handles the requested url, I want to check the user status. If the user isn't authenticated, I want to save the requested url and redirect to a specific url (/login).
I tried to implement this overloading Ember.Route but I don't think it's a good practice.
For example, if i do:
var AuthRoute = Ember.Route.extend({
redirect: function() {
var controller = App.userController;
if (!controller.get("userAuth")) {
controller.set("lastFilter", this.routeName);
this.transitionTo("index");
}
}
}
});
If, the url is '/admin/foobar', the admin route will redirect instead of foobar.
Can I process redirection before the Router to start?
I use something like this
Ember.SecureRoute = Ember.Route.extend({
role: null,
redirect: function (model) {
if (!this.controllerFor('login').get('authenticated')) {
this._routeToLogin();
}
var role = this.get('role');
if (!Ember.isEmpty(role) && !this.controllerFor('login').hasRole(role)) {
this._routeToLogin();
}
},
_routeToLogin: function () {
var infos = this.get('router.router.currentHandlerInfos');
this.router.router.didTransition(infos);
var routeName = !this.router.router.hasRoute(this.routeName) ? this.routeName + '.index' : this.routeName;
var params = infos.filter(function (item, index, enumerable) { return item.context !== undefined; }).map(function (item) { return item.context; })
var url = Ember.Router.prototype.generate.apply(this.router, params.insertAt(0, routeName))
this.router.location.setURL(url);
this.transitionTo("login");
}
});
in your loginController you can then use the browser history to go back to your original route
APP.LoginController = Ember.Controller.extend({
//other stuff
authenticate: function (username, password) {
//do the authentication
history.go(-1);
}
});
The way that I do it is I pass down the authenticated user with my data. and I have an initConfiguration function inside of my main App
so inside of index file (in this case I am showing you jade) I have this:
// initialize ember settings
script(type='text/javascript')
App.initConfiguration('!{currentUser}')
and inside of my App file I have (coffeescript here)
window.App = Ember.Application.create
currentUser: null
initConfiguration: (currentUser) ->
if currentUser? and currentUser.length > 0
#set 'currentUser', currentUser
If you are using ember-data, then you have to change the application file to
window.App = Ember.Application.create
currentUser: null
tempCurrentUser: null
initConfiguration: (currentUser) ->
##
# set the tempCurrentUser to the currentUser passed in, this is then
# set in the ApplicationRoute to the App.currentUser
# and destroyed (this is necessary as the ember store is not initialzed yet
# and just setting it here will result in an error)
if currentUser? and currentUser.length > 0
#set 'tempCurrentUser', currentUser
and then inside your application route do the following
App.ApplicationRoute = Ember.Route.extend
setupController: (controller) ->
if App.tempCurrentUser?
App.setCurrentUser(App.tempCurrentUser)
Ember has a fantastic guide on preventing and retrying authentication: http://emberjs.com/guides/routing/preventing-and-retrying-transitions/
A simple way to do transitions based on whether or not a user is logged in:
App.ApplicationRoute = Ember.Route.extend({
willTransition: function () {
var session = this.controllerFor('session');
if (!session.get('authed')) {
this.transitionTo('login');
}
}
});
The example above assumes you have some kind of session controller or object managing the active sessions. This works because the ApplicationRoute is the very first route that is hit whenever you enter your application (from any URL).