2

In my EmberJS application, I have a current user initializer, which injects the user into all controllers, routes, and views. It works great when logged in. I need the synchronous loading of the current user object so I can check some user permissions right off the bat.

Here's my initializer:

App.CurrentUserInitializer - Ember.Initializer.extent({

    name: 'current-user',
    after: 'authentication',

    initialize: function(container, app) {

      var store = container.lookup('store:main');

      app.deferReadiness();

      store.find('user', 'me').then(function (user) {

        app.register('session:user', user, {instantiate: false});

        _.forEach(['route', 'controller', 'view'], function (place) {
          app.inject(place, 'currentUser', 'session:user');
        });

        app.advanceReadiness();

      }).catch(function () {
        app.advanceReadiness();
      });
    }
});

Where this breaks down for me, is during login. When the app boots, the initializer is run, but the /users/me route returns a 401 error. If I don't catch the error and advanceReadiness, booting halts. By catching the error, the app boots, but the initializer isn't run again after login, so the current user isn't loaded.

What are my options here? I can't use @marcoow's recommended method of adding a computed property to the Session, as I need the user loaded at boot time.

I've tried forcing loading the user object on the IndexRoute as a hack, but that doesn't seem to work.

Any tips are appreciated.

4

1 回答 1

5

我会注册一个属性为空的session:current对象。user这将被注入controllersroutes(不确定注入内部视图是一个好主意)。

所以在启动时user是未知的,但用户查找是在路由器比路由更深之前完成的application,根:

在路线的beforeModel挂钩中application,您将加载该当前用户。然后:

  • 要么你得到了用户然后你设置它this.set('session.user', model)
  • 或者你会进入路由的error钩子application,在这种情况下你必须检查原因,如果401这样你可以将用户重定向到登录路由this.transitionTo('login')

session如果你得到了,不要忘记设置一个标志,401这样transitionTo我们的用户查找beforeModel就不会再次发生,直到我们到达login路线

用于加载会话用户并对其进行初始化的代码可以放在该session:current对象中,以便您可以从application路由或login控制器调用它。

例如,这是我的session初始化程序(不完全像我解释的那样,而是加载初始化程序,因此更接近您所拥有的)。我使用了一个session模型,以便我这样做/session/current,然后让一个用户进入它(或没有),它具有正确的 id 而不是me这会使商店加载具有另一个 id 的同一用户,因此具有两倍于 2 的相同用户不同的记录:

应用程序/模型/session.js

import DS from 'ember-data';
import Ember from 'ember';

export default DS.Model.extend({
  user:            DS.belongsTo('user'),
  isAuthenticated: Ember.computed.bool('user.isClaimed')
});

应用程序/初始化程序/session.js

import Ember from 'ember';

export default {
  name:  'session',
  after: 'store',

  initialize: function (container, app) {
    var store = container.lookup('store:main'),
        sid = Ember.$.cookie('sid');
    // used to register a session
    var register = function (session) {
      app.register('session:main', session, {instantiate: false});
      app.inject('route', 'session', 'session:main');
      app.inject('controller', 'session', 'session:main');
    };
    // used to create a new session and trigger the backend to get details about it
    // useful if the server is able to give an existing session while the browser doesn't know about it
    // with external providers for example
    var newSession = function () {
      var session = store.createRecord('session');
      // be sure to wipe out any invalid session ID
      Ember.$.removeCookie('sid');
      register(session);
      return session.save().then(function (model) {
        // if we got a valid new session, save its ID
        Ember.$.cookie('sid', model.get('id'));
      }).catch(function () {
        Ember.debug('error saving new session: ' + Array.prototype.join.call(arguments, ', '));
      });
    };
    // overall logic ==================
    app.deferReadiness();
    if (sid) {
      // try to load the existing session
      store.find('session', sid).then(function (model) {
        register(model);
        app.advanceReadiness();
      }).catch(function () {
        // there was a cookie for the session but it might have expired or the server invalidated it
        Ember.debug('error loading session: ' + Array.prototype.join.call(arguments, ', '));
        newSession().finally(function () {
          app.advanceReadiness();
        });
      });
    }
    else {
      // we don't have any trace of a session, let's just create a new one
      newSession().finally(function () {
        app.advanceReadiness();
      });
    }
  }
};

应用程序/路由器.js

import Ember from 'ember';

var Router = Ember.Router.extend();

Router.map(function () {
  this.resource('session', {path: '/'}, function(){
    this.route('login');
    this.route('logout');
  });
});

export default Router;

app/templates/application.hbs(例如):

<h2 id='title'>Welcome to my app</h2>
{{#if session.isAuthenticated}}
  <a {{action 'session.logout'}}>Logout</a>
{{else}}
  {{#link-to 'session.login'}}Login{{/link-to}}
{{/if}}
{{outlet}}

然后一旦进入登录控制器,当用户实际登录时,服务器将返回session带有用户链接的模型,因此 Ember 绑定魔法只会更新会话对象。

于 2014-09-23T14:16:25.110 回答