7
votes

I'm trying to to get a list of all defined models in my Ember application (v1.8).

As far as I can tell from my research, the Container.resolver works with some mysterious magic. Does the Container have a list of all active models, or is there any way to get them?

Thanks :)

@edit

kingpin2k's answer works, but not in Ember-Cli, is there an other way?

4
What do you mean by active models? Like Ember Data defined models?Kingpin2k
Yes, all models I defined.medokin
I'm also at loss at this (ember-cli). At first I thought this.container.resolveCache was the solution but it doesn't have all the models at my entry point :( Did you find a solution?Alexandre Gomes

4 Answers

7
votes

So, for Ember Cli there isn't a direct solution I could find. However, you can work around the problem with a bit of creative coding and by analysing ember-inspector's source.

var models = Object.keys(require._eak_seen).filter(function(module) {
    return module.indexOf(config.modulePrefix + '/models/') === 0;
});

This snippet iterates over the modules registered with requirejs and extracts only the wanted modules (the models in our case).

For the "config.modulePrefix" part to work you will need to import your conf file (fix the path):

import config from '../config/environment';

Alternatively you can either hardcode the "config.modulePrefix" to "myappname" or use this:

this.container.resolver.__resolver__.namespace.modulePrefix

PS: To inspect the model you need to use:

require(_the_model_module_name).default
7
votes

So I'm adding this, because I came across what I believe is now the best solution (post ember-cli, and ember container changes):

// in a route
// routes/route.js
import Ember from 'ember'

const { Route, getOwner } = Ember

export default Route.extend({
  model: function(){
    return getOwner(this)
    .lookup('data-adapter:main')
    .getModelTypes()
    .map(type => type.name)
  }
})

// somewhere else in an ember application
const modelNames = getOwner(this)
.lookup('data-adapter:main')
.getModelTypes()
.map(type => type.name)

Here is the link to the source in ember-admin on github.

4
votes

Really, the easiest would be to just iterate your namespace and look for objects whose super class is DS.Model

 for (var key in App) {
      var value = App[key],
          superClass = value ? value.superclass : undefined;

      if (superClass && superClass === DS.Model) {
        console.log(value);     
      }
 }

http://emberjs.jsbin.com/OxIDiVU/899/edit

4
votes

In trying to do this specficically in an initializer, here's what I found (using ember-cli version 1.13.8 with Ember 2.1.0 -- i.e. current as of today):

tl;dr:

From within your code (eg. my instance intializer):

import ModuleRegistry from 'ember-resolver/utils/module-registry';
    ...
var modelRegexp = /^[a-zA-Z0-9-_]+\/models\/(.*)$/;
var modelNames = new ModuleRegistry()
  .moduleNames()
  .filter((name) => modelRegexp.test(name))
  .map((name) => modelRegexp.exec(name)[1]);

If you need a hacky one-liner from the debugging console on a running app:

YourAppName.__container__
  .lookup('container-debug-adapter:main')
  .catalogEntriesByType('model')
  .filter((name) => YourAppName.__container__.lookupFactory('model:' + name));

Or, get only the models already loaded (is that what you mean by "active models"?) with:

Object.keys(YourAppName.__container__.factoryCache).filter((i) => i.startsWith('model:'))

Longer answer:

These approaches are kind of complicated, assume you aren't using pods or anything else non-standard, and rely on undocumented internal APIs. They're also specific to ember-resolver (the ES6-module-based lookup system used in ember-cli and Ember App Kit). So not ideal.

It should actually be as simple as:

var debugAdapter = appInstance.lookup('container-debug-adapter:main');
var modelNames = debugAdapter.catalogEntriesByType('model');

Unfortunately the ContainerDebugAdapter class included with ember-resolver is buggy, so it will return a bunch of extra items.

Hopefully this will be fixed soon (I've filed bug report), but until then, the code above should serve.

Interestingly, this string-based matching is basically what the ContainerDebugAdapter does (incorrectly) internally. The ContainerDebugAdapter that ships with Ember does the same sort of thing to look up objects in the app-wide namespaces (Ember.Namespace.NAMESPACES).

I realize that Ember (and ember-cli especially) is very name-convention-driven, but this regex matching feels a little crazy. It seems to me that, ideally, we'd instead be importing the DS.Model class and just getting it's subclasses. Unfortunately it seems that isn't (easily) possible: as far as I can tell, an Ember class stores a reference to it's superclass(es), but not to it's subclasses.