Adapter updates in beta-16.1?


#1

Hey friends,

Hoping someone can help spot the issue I’m having or maybe point me in the right direction. In my app, we use a repository pattern to alter the namespace for certain requests. An example would be when we want to make a request to https://apiserver.com/v1/users/:id/workspaces. By default my adapter namespace is set to v1. Prior to sending the request with ember-data, I append users/:id to the namespace of the adapter, then send the request with store.find('workspace'). Up until ember-data 1.0.0-beta.15, this approach has worked swimmingly. I find that after upgrading to beta-16.1 that the namespace alteration isn’t picked up by the buildURL method, or I suppose it occurs after buildURL is run.

  • Is it possible that this has anything to do with the Snapshot API?
  • With the new injection method in initializers, could that have anything to do with it? I’m not doing any container.lookup in the initializer, so this may be a non-issue.
// repositories/workspace.js
  appendResources: function () {
    this.clearAppendedResources();

    var adapterNamespace = this.get('adapter.namespace'), // We're injecting the adapter into repositories
        prefix = [adapterNamespace];

    if (arguments.length) {
      // For each argument, lookup the related id. Push both to the namespace
      for (var i=0; i < arguments.length; i++) {
        prefix.push(arguments[i]);
      }
      this.set('adapter.namespace', prefix.join('/'));
    }
  },

  // The method that ties it all together
  getWorkspacesByUser: function (user_id, params) {
    var self = this;

    if (params === undefined) {
      params = {};
    }

    this.appendResources('users', user_id); // We alter the namespace here
    this.setupIncludes(); // We append some ?include=yadayada params here

    // Make the request! Should be to /v1/users/:id/workspaces
    return this.store.find('workspace', params).finally(function () {
      // Clean up all the things
      self.clearIncludes();
      self.clearAppendedResources();
    });
  }

Here’s how we’re building the URL in the adapter for reference:

  // adapters/workspace.js
  buildURL: function(type, id, snapshot) {
    var url = this._super(type, id, snapshot);
    return this.buildIncludeURL(url);
  },

  buildIncludeURL: function (url) {
    if (this.includes.length) {
      url += '?include=' + this.includes.join(',');
    }
    return url;
  }

#2

Yu say you’re injecting the adapter into repositories?

The adapters and serialisers have changed in that they are no longer singleton. Each instance of a store maintains its own serialiser and adapter instances… This might be part of your problem - your altering an injected adapter while requests are using a different adapter (one your store has created)


#3

That’s interesting and the most logical conclusion. So when requests are made the store, a new instance of an adapter and serializer is instantiated for each request?


#4

Nope - the store maintains a single instance. It uses that one instance for each request.

When calling store.adapterFor('workspace') you will always get back the same instance.


#5

Ah. Sorry for my lack of knowledge about ED core. I’m assuming this means adapters are no longer registered with the container and bound directly to the model instance?

Is there a specific place/source file I should look at so I can grok this without asking you a bo-jillion questions?


#6

Adapters are still registered against the container - they initially come from the container - when the store first creates them…

You could look at this pull request which is the one that implemented this particular change - but don’t mind me - if you have any more questions (and I’m capable of answering) I’m happy to help (:


#7

So the benefit of having adapters and serializers not registered as singletons is to prevent collisions between apps using multiple stores or stores registered other than store:main? Neat. So another question…if I want to affect some properties on the adapter or serializer prior to making a request, would it be best to lookup the specific adapter instance with store.adapterFor(‘type’)?

p.s. Great work on that PR. You da man.


#8

The whole thing started because the EmbeddedRecordMixin used the store property which was always the store:main - so there was no way to get embedded records in a store other than store:main.

store.adapterFor('type') is the way to go - yep.