Bootstrapping app with data

I have been struggling with bootstrapping an app. Specifically I am trying to bootstrap an authenticated user account. This is a Rails app and getting the serialized attributes on the model isn’t an issue however getting that data in to the store seems to be difficult.

Currently I am using ember-data revision 12. When I create a new application I don’t seem to have access to the instance of the store on the App object. Only App.Store which is the class. I can get to the store instance if I go through App.__container__ but I obviously don’t want to do this.

Beyond that, I have noticed that the store does not block when being created. So when I have bootstrap code that runs after the app is created the store may or may not be available. For the time being I have created a new Ember.Application.initializer to run and the store is available then but I would like to know if there is a better way to do this.

So to sum up:

  1. What is the best way to bootstrap data?
  2. How do I access the instance of the store from the App object?
  3. What is the best way to ensure the store instance have been created before I attempt to bootstrap?

If you only have one store you can access it through DS.get('defaultStore').

Out bootstrap initializer looks something like this:

App.initializer({
    name: 'appBootstrap',
    initialize: function() {
        App.deferReadiness();
        $.get('/user/bootstrap', function(payload) {
            var store = DS.get('defaultStore');
            //User
            store.load(App.User, payload.user);
            App.session.set('user', App.User.find(payload.user.id));
            //Other
            store.loadMany(App.Currency, payload.currencies);
            store.loadMany(App.Country, payload.countries);
            //Initialize app
            App.advanceReadiness();
        });
    }
});

/user/bootstrap returns everything needed to start the app. To save some requests we include all countries and currencies in the bootstrap response. We have an object, App.session which is responsible for holding information about the currently authenticated user.

You should not try to use the store before the app has been initialized.

6 Likes

That makes sense. Thank you

@seilund Could you please explain the benefits or differences when to do something like this?

App.ApplicationRoute = Ember.Route.extend({
  enter: function() {
    this.controllerFor('currencies').set('content', App.Currency.find());
    this.controllerFor('countries').set('content', App.Country.find());
  }
});

I understand that this example would send two separate HTTP request, but I am trying to understand why you choose an App.initializer instead of an App.ApplicationRoute. Thanks.

Good question. The real reason why we use an initializer is not the currencies or countries. In our app the user has one or more organizations. Before we can show anything useful to the user we need to load all the organizations which are also included in /user/bootstrap. The App.IndexRoute redirects to a subroute App.OrganizationRoute which has a url like /:organization_id/dashboard. Without any organizations, there would be nothing to redirect to.

The currencies and countries are only loaded as a small performance optimization. We load around 10 different entity types that are more or less static.

Loading this stuff and the user + organizations also avoids showing missing data for the first couple hundreds miliseconds after the app initializes and before 10 requests are fulfiled.

I’ve actually been doing the same/similar thing here as @seilund. Though, I’ve added multiple initializers for each item I’m bootstrapping – I’m not sure if that’s correct now, but it works and it seemed like an embery thing to do.

The only other thing is I’ve been outputting the bootstrap json into a preload variable on pageload and saving myself an http request.

Curious to hear others thoughts as well