How to fix: Module ‘ngStorage’ is not available!

Well, this is a fun one.

Quite an easy fix – pay more attention to the manual!

The error:

Uncaught Error: [$injector:modulerr] Failed to instantiate module yourAppNameHere due to:
Error: [$injector:modulerr] Failed to instantiate module ngStorage due to:
Error: [$injector:nomod] Module 'ngStorage' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.4.6/$injector/nomod?p0=ngStorage
    at REGEX_STRING_REGEXP (http://localhost:3000/bower_components/angular/angular.js:68:12)
    at http://localhost:3000/bower_components/angular/angular.js:1986:17
    at ensure *snip*

The fix:

In my case, the fix was to install ngstorage not ngStorage – note the capital ‘S’ in the ‘bad’ variant.

It’s actually right there in the manual :/

bower install ngstorage manual entry

(Shame face)

Assuming you are installing using Bower, you want to ensure you are seeing something similar to the following:

bower install ngstorage

Note the reference to gsklee.

And you should be good to go.

Is 6 GBs Enough GB?

6gbs-too-few-gbsLately, I have found myself asking the time old question 😉 :

Is 6 GB enough GB?

And of course, the answer is: No.

6 GB is too few GB for any software developer who values their time and sanity.

Oh, you want to open a browser AND your IDE?

No chance. Don’t be such a prima donna.

I know, I know, that’s a Windows memory indicator. That’s only adding to the problem 😉

But check out this nasty Ubuntu swappy leaky situation:

ubuntu-greedy-swap-issue

Every day I am mysteriously losing 500 or more MB to the Swap. It never comes back.

I have my suspicions that Firefox Developer Edition is to blame but that’s so far, just conjecture.

 

Ubuntu No Sound in one Profile in Ubuntu 15.04

Ubuntu No Sound in 15.04Ok, so not truly related to the site in general, but it’s computers in general, and more specifically, my broken computer.

Recently, I made a late night decision to upgrade from a perfectly stable, working Ubuntu 14.04 to Ubuntu 15.04… what could go wrong?

A lot, as it happens. Two full rebuilds later (thank the Lord for putting /home on it’s own HDD), and I have just about recovered something resembling a working PC.

The last major hurdle was having no sound.

Ubuntu No Sound

Frustratingly, I could hear the little boot jungle drums of Ubuntu. Then if I logged in as me, no sound at all.

If I logged in as Guest, I could hear some sound. That narrowed it down.

After much Googling and frustration, this fixed it:

Open terminal
rm -rf ~/.config/pulse
Reboot

Hurrah, sound is back.

Models not working in Loopback Passport Module

I’ve been having a heck of a time trying to get Passport, or more specifically, the Loopback Passport Component to work with my Strongloop API project.

I should say, this is an existing project into which I have installed the loopback passport component (npm i loopback-component-passport --save) rather than using the Loopback Passport Example – which I also have had plenty of problems with.

Today’s error was when loading the Strongloop Composer (v1.8.1), I could see my datasources, but the models were empty:

strongloop-loopback-empty-models-in-slc-arc

When opening up the Chrome developer tools > console, I could see this:

TypeError: Cannot read property 'dataSource' of undefined
    at Array. (model.services.js:179)
    at Object.forEach (angular.js:323)
    at model.services.js:161
    at angular-resource.js:627
    at processQueue (angular.js:13248)
    at angular.js:13264
    at Scope.parent.$get.Scope.$eval (angular.js:14466)
    at Scope.parent.$get.Scope.$digest (angular.js:14282)
    at Scope.scopePrototype.$digest (hint.js:1955)
    at Scope.parent.$get.Scope.$apply (angular.js:14571)

But Googling this error wasn’t coming up with much in the way of suggestions.

Another strange thing was that I could add in a new Model, save it, but then if I refreshed the page, it would disappear. The model itself had been created in the common/models dir. I could see the .js and .json files in my WebStorm project, and if I tried to create a new Model with the same name it wouldn’t let me. But the slc arc Composer just wouldn’t display them.

Though I cannot remember exactly how I was getting to this point, I was also infrequently seeing errors in the console, with this error message:

{"error":{"name":"Error","status":404,"message":"Unknown "DataSourceDefinition" id "undefined".","statusCode":404,"code":"MODEL_NOT_FOUND","stack":"Error: Unknown "DataSourceDefinition" id "undefined".\n    at Function.convertNullToNotFoundError (/usr/local/lib/node_modules/strongloop/node_modules/loopback/lib/persisted-model.js:81:17)\n    at invokeRestAfter (/usr/local/lib/node_modules/strongloop/node_modules/loopback/node_modules/strong-remoting/lib/rest-adapter.js:445:25)\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:607:21\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:246:17\n    at iterate (/usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:146:13)\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:157:25\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:248:21\n    at /usr/local/lib/node_modules/strongloop/node_modules/async/lib/async.js:612:34\n    at /usr/local/lib/node_modules/strongloop/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:626:11\n    at execStack (/usr/local/lib/node_modules/strongloop/node_modules/loopback/node_modules/strong-remoting/lib/remote-objects.js:460:7)"}}

I’m leaving that in, in the hope that any future Googlers may save themselves some time.

My Fix

To get this working I ended up creating a brand new project (slc loopback) and then piece by piece, copying my existing project across and watching for where it broke.

It turns out it was largely the Passport module config that was breaking the project, so here are the relevant, working files:

Check your versions. Loopback changes a lot.

// package.json
{
  "name": "tester",
  "version": "1.0.0",
  "main": "server/server.js",
  "scripts": {
    "pretest": "jshint ."
  },
  "dependencies": {
    "compression": "^1.0.3",
    "cors": "^2.5.2",
    "errorhandler": "^1.1.1",
    "express-session": "^1.11.3",
    "loopback": "^2.14.0",
    "loopback-boot": "^2.6.5",
    "loopback-component-passport": "^1.5.0",
    "loopback-connector-mysql": "^2.2.0",
    "loopback-datasource-juggler": "^2.19.0",
    "passport-local": "^1.0.0",
    "passport-tumblr": "^0.1.2",
    "serve-favicon": "^2.0.1"
  },
  "optionalDependencies": {
    "loopback-explorer": "^1.1.0"
  },
  "devDependencies": {
    "jshint": "^2.5.6"
  },
  "repository": {
    "type": "",
    "url": ""
  },
  "description": "tester"
}

In the model-config.json, note the inclusion of "./node_modules/loopback-component-passport/lib/models" in the meta > sources, the UserCredential, and UserIdentity models:

// server/model-config.jsom
{
  "_meta": {
    "sources": [
      "loopback/common/models",
      "loopback/server/models",
      "../common/models",
      "./models",
      "./node_modules/loopback-component-passport/lib/models"
    ],
    "mixins": [
      "loopback/common/mixins",
      "loopback/server/mixins",
      "../common/mixins",
      "./mixins",
      "../node_modules/loopback-ds-timestamp-mixin"
    ]
  },
  "User": {
    "dataSource": "db",
    "public": true
  },
  "AccessToken": {
    "dataSource": "db",
    "public": false
  },
  "ACL": {
    "dataSource": "db",
    "public": false
  },
  "RoleMapping": {
    "dataSource": "db",
    "public": false
  },
  "Role": {
    "dataSource": "db",
    "public": false
  },
  "UserCredential": {
    "dataSource": "db",
    "public": false
  },
  "UserIdentity": {
    "dataSource": "db",
    "public": false
  },
  "user": {
    "dataSource": "db",
    "public": true
  },
  "userCredential": {
    "dataSource": "db",
    "public": true
  },
  "userIdentity": {
    "dataSource": "db",
    "public": true
  },
  "accessToken": {
    "dataSource": "db",
    "public": true
  },
  "acl": {
    "dataSource": "db",
    "public": true
  },
  "roleMapping": {
    "dataSource": "db",
    "public": true
  },
  "role": {
    "dataSource": "db",
    "public": true
  },
  "scope": {
    "dataSource": "db",
    "public": true
  }
}

Why the duplicates, e.g. User and user?

Well, you have to define the base model, and then your own model which extends the base. But both have to be defined.

This bit left me confused, so here are each of the relevant models for reference:

// common/models/access-token.json 
{
  "name": "accessToken",
  "plural": "accessTokens",
  "base": "AccessToken",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/acl.json 
{
  "name": "acl",
  "plural": "acls",
  "base": "ACL",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/role.json
{
  "name": "role",
  "plural": "roles",
  "base": "Role",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/role-mapping.json
{
  "name": "roleMapping",
  "plural": "roleMappings",
  "base": "RoleMapping",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/scope.json
{
  "name": "scope",
  "plural": "scopes",
  "base": "Scope",
  "properties": {},
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/user.json
{
  "name": "user",
  "plural": "users",
  "base": "User",
  "properties": {
    "accessTokens": {
      "type": "hasMany",
      "model": "accessToken",
      "foreignKey": "userId"
    },
    "identities": {
      "type": "hasMany",
      "model": "userIdentity",
      "foreignKey": "userId"
    },
    "credentials": {
      "type": "hasMany",
      "model": "userCredential",
      "foreignKey": "userId"
    }
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}
// common/models/user-credential.json
{
  "name": "userCredential",
  "plural": "userCredentials",
  "base": "UserCredential",
  "properties": {},
  "validations": [],
  "relations": {
    "user": {
      "type": "belongsTo",
      "model": "user",
      "foreignKey": "userId"
    }
  },
  "acls": [],
  "methods": []
}
// common/models/user-identity.json
{
  "name": "userIdentity",
  "plural": "userIdentities",
  "base": "UserIdentity",
  "properties": {},
  "validations": [],
  "relations": {
    "user": {
      "type": "belongsTo",
      "model": "user",
      "foreignKey": "userId"
    }
  },
  "acls": [],
  "methods": []
}

Once the models are displaying again, feel free to change the datasources:

// server/datasources.json 
{
  "db": {
    "name": "db",
    "connector": "memory"
  },
  "mysql": {
    "host": "your.server.ip.here",
    "database": "dbname",
    "password": "dbpassword",
    "name": "mysql",
    "connector": "mysql",
    "user": "dbuser"
  }
}

Note, those are the settings created by Strongloop slc arc. If you enter them manually, using the data / fields in the manual, you may end up with duplicates – e.g. user and username.

My Loopback Passport Module Config

And lastly, and probably the most important is the server.js file.

// server/server.js
var loopback = require('loopback');
var boot = require('loopback-boot');

var app = module.exports = loopback();

var PassportConfigurator = require('loopback-component-passport').PassportConfigurator;
var passportConfigurator = new PassportConfigurator(app);

app.start = function() {
  // start the web server
  return app.listen(function() {
    app.emit('started');
    console.log('Web server listening at: %s', app.get('url'));
  });
};

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function(err) {
  if (err) throw err;

  // start the server if `$ node server.js`
  if (require.main === module)
    app.start();
});

// Enable http session
app.use(loopback.session({ 
  secret: 'keyboard cat',  
  resave: true,
  saveUninitialized: true 
}));

// Load the provider configurations
var config = {};
try {
  config = require('./providers.json');
} catch(err) {
  console.error('Please configure your passport strategy in `providers.json`.');
  console.error('Copy `providers.json.template` to `providers.json` and replace the clientID/clientSecret values with your own.');
  process.exit(1);
}
// Initialize passport
passportConfigurator.init();

// Set up related models
passportConfigurator.setupModels({
  userModel: app.models.User,
  userIdentityModel: app.models.UserIdentity,
  userCredentialModel: app.models.UserCredential
});
// Configure passport strategies for third party auth providers
for(var s in config) {
  var c = config[s];
  c.session = c.session !== false;
  passportConfigurator.configureProvider(s, c);
}

The ordering here seems to be the most important part.

If your passport config tries to call the models before they are ready, that seems to cause a lot of problems. It sounds obvious in hindsight, but when you have a lot of things going on in your server.js file, sometimes it can be hard to see the wood for the trees.