Deprecations Added in Ember Data 4.x

What follows is a list of deprecations introduced to Ember Data during the 4.x cycle.

For more information on deprecations in Ember Data, see the main deprecations page.

Deprecations Added in 4.4

§ Model Save Promise

until: 5.0
id: ember-data:model-save-promise

Affects:

  • model.save / store.saveRecord
  • model.reload

Deprecates the promise-proxy returned by these methods in favor of a Promise return value.

To resolve this deprecation, await or .then the return value before doing work with the result instead of accessing values via the proxy.

To continue utilizing flags such as isPending in your templates consider using ember-promise-helpers

Deprecations Added in 4.5

§ Deprecate Has Record For Id

until: 5.0
id: ember-data:deprecate-has-record-for-id

Deprecates store.hasRecordForId(type, id) in favor of store.peekRecord({ type, id }) !== null.

Broadly speaking, while the ability to query for presence is important, a key distinction exists between these methods that make relying on hasRecordForId unsafe, as it may report true for a record which is not-yet loaded and un-peekable. peekRecord offers a safe mechanism by which to check for whether a record is present in a usable manner.

§ Deprecate Secret Adapter Fallback

until: 5.0
id: ember-data:deprecate-secret-adapter-fallback

Deprecates the secret -json-api fallback adapter in favor or an explicit "catch all" application adapter. In addition to this deprecation ensuring the user has explicitly chosen an adapter, this ensures that the user may choose to use no adapter at all.

Simplest fix:

/app/adapters/application.js
export { default } from '@ember-data/adapter/json-api';

§ Deprecate Snapshot Model Class Access

until: 5.0
id: ember-data:deprecate-snapshot-model-class-access

Deprecates accessing the factory class for a given resource type via properties on various classes.

Guards:

  • SnapshotRecordArray.type
  • Snapshot.type
  • RecordArray.type

Use store.modelFor(<resource-type>) instead.

§ Deprecate Promise Many Array Behaviors

until: 5.0
id: ember-data:deprecate-promise-many-array-behaviors

Deprecates store.hasRecordForId(type, id) in favor of store.peekRecord({ type, id }) !== null.

Broadly speaking, while the ability to query for presence is important, a key distinction exists between these methods that make relying on hasRecordForId unsafe, as it may report true for a record which is not-yet loaded and un-peekable. peekRecord offers a safe mechanism by which to check for whether a record is present in a usable manner.

§ Deprecate String Arg Schemas

until: 5.0
id: ember-data:deprecate-string-arg-schemas

Deprecates schema.attributesDefinitionFor(type) and schema.relationshipsDefinitionFor(type) in favor of a consistent object signature (identifier | { type }).

To resolve change:

- store.getSchemaDefinitionService().attributesDefinitionFor('user')
+ store.getSchemaDefinitionService().attributesDefinitionFor({ type: 'user' })

§ Rsvp Unresolved Async

until: 5.0
id: ember-data:rsvp-unresolved-async

Deprecates when a request promise did not resolve prior to the store tearing down.

Note: in most cases even with the promise guard that is now being deprecated a test crash would still be encountered.

To resolve: Tests or Fastboot instances which crash need to find triggers requests and properly await them before tearing down.

Deprecations Added in 4.7

§ Deprecate Array Like

until: 5.0
id: ember-data:deprecate-array-like

Deprecates Ember "Array-like" methods on RecordArray and ManyArray.

These are the arrays returned respectively by store.peekAll(), store.findAll() and hasMany relationships on instance of Model or record.hasMany('relationshipName').value().

The appropriate refactor is to treat these arrays as native arrays and to use native array methods.

For instance, instead of:

users.firstObject;

Use:

users[0];
// or
users.at(0);

§ Deprecate Early Static

until: 5.0
id: ember-data:deprecate-early-static

This deprecation triggers if static computed properties or methods are triggered without looking up the record via the store service's modelFor hook. Accessing this static information without looking up the model via the store most commonly occurs when:

  • using ember-cli-mirage (to fix, refactor to not use its auto-discovery of ember-data models)
  • importing a model class and accessing its static information via the import

Instead of:

import User from 'my-app/models/user';

const relationships = User.relationshipsByName;

Do at least this:

const relationships = store.modelFor('user').relationshipsByName;

However, the much more future proof refactor is to not use modelFor at all, but instead to utilize the schema service for this static information:

const relationships = store
  .getSchemaDefinitionService()
  .relationshipsDefinitionFor({ type: 'user' });

§ Deprecate Errors Hash To Array Helper

until: 5.0
id: ember-data:deprecate-errors-hash-to-array-helper

Deprecates errorsHashToArray errorsArrayToHash and normalizeModelName.

Users making use of these (already private) utilities can trivially copy them into their own codebase to continue using them, though we recommend refactoring to a more direct conversion into the expected errors format for the errors helpers.

For refactoring normalizeModelName we also recommend following the guidance in RFC#740 Deprecate Non-Strict Types.

§ Deprecate Errors Hash To Array Helper

until: 5.0
id: ember-data:deprecate-errors-hash-to-array-helper

Deprecates errorsHashToArray errorsArrayToHash and normalizeModelName.

Users making use of these (already private) utilities can trivially copy them into their own codebase to continue using them, though we recommend refactoring to a more direct conversion into the expected errors format for the errors helpers.

For refactoring normalizeModelName we also recommend following the guidance in RFC#740 Deprecate Non-Strict Types.

§ Deprecate Model Reopen

until: 5.0
id: ember-data:deprecate-model-reopen

For properties known ahead of time, instead of:

class User extends Model {
  @attr firstName;
}

User.reopen({ lastName: attr() });

Extend User again or include it in the initial definition:

class User extends Model {
  @attr firstName;
  @attr lastName;
}

For properties generated dynamically, consider registering a SchemaDefinitionService with the store, as such services are capable of dynamically adjusting their schemas, and utilize the instantiateRecord hook to create a Proxy based class that can react to the changes in the schema. Use Foo extends Model to extend your class instead.

§ Deprecate Model Reopenclass

until: 5.0
id: ember-data:deprecate-model-reopenclass

Instead of reopenClass, define static properties with native class syntax or add them to the final object.

Instead of:

User.reopenClass({ aStaticMethod() {} });

Do this:

class User {
  static aStaticMethod() {}
}

Or, do this:

User.aStaticMethod = function () {};

§ Deprecate Non Strict Relationships

until: 5.0
id: ember-data:deprecate-non-strict-relationships

Deprecates when belongsTo and hasMany relationships are defined without specifying whether the relationship is asynchronous.

The current behavior is that relationships which do not define this setting are aschronous ({ async: true }).

Instead of:

class Company extends Model {
  @hasMany('employee') employees;
}

class Employee extends Model {
  @belongsTo('company') company;
}

Use:

class Company extends Model {
  @hasMany('employee', { async: true, inverse: 'company' }) employees;
}

class Employee extends Model {
  @belongsTo('company', { async: true, inverse: 'employees' }) company;
}

Also deprecates when belongsTo and hasMany relationships are defined without specifying the inverse field on the related type.

The current behavior is that relationships which do not define this setting have their inverse determined at runtime, which is potentially non-deterministic when mixins and polymorphism are involved.

If an inverse relationship exists and you wish changes on one side to reflect onto the other side, use the inverse key. If you wish to not have changes reflected or no inverse relationship exists, specify inverse: null.

Instead of:

class Company extends Model {
  @hasMany('employee') employees;
}
class Employee extends Model {
  @belongsTo('company') company;
}

Use:

class Company extends Model {
  @hasMany('employee', { async: true, inverse: 'company' }) employees;
}

class Employee extends Model {
  @belongsTo('company', { async: true, inverse: 'employees' }) company;
}

Instead of:

class Company extends Model {
  @hasMany('employee') employees;
}
class Employee extends Model {
  @attr name;
}

Use:

class Company extends Model {
  @hasMany('employee', { async: true, inverse: null }) employees;
}

class Employee extends Model {
  @attr name;
}

And also deprecates when belongsTo and hasMany relationships are defined without specifying the inverse record's type.

Instead of

class Company extends Model {
  @hasMany() employees;
}

class Employee extends Model {
  @belongsTo() company;
}

Use

class Company extends Model {
  @hasMany('employee', { async: true, inverse: 'company' }) employees;
}

class Employee extends Model {
  @belongsTo('company', { async: true, inverse: 'employees' }) company;
}

§ Deprecate Promise Many Array Behaviors

until: 5.0
id: ember-data:deprecate-promise-many-array-behaviors

Deprecates errorsHashToArray errorsArrayToHash and normalizeModelName.

Users making use of these (already private) utilities can trivially copy them into their own codebase to continue using them, though we recommend refactoring to a more direct conversion into the expected errors format for the errors helpers.

For refactoring normalizeModelName we also recommend following the guidance in RFC#740 Deprecate Non-Strict Types.

§ Deprecate Promise Many Array Behaviors

until: 5.0
id: ember-data:deprecate-promise-many-array-behaviors

RFC Documentation

This deprecation deprecates accessing values on the asynchronous proxy in favor of first "resolving" or "awaiting" the promise to retrieve a synchronous value.

Template iteration of the asynchronous value will still work and not trigger the deprecation, but all JS access should be avoided and HBS access for anything but {{#each}} should also be refactored.

Recommended approaches include using the addon ember-promise-helpers, using Ember's resource pattern (including potentially the addon ember-data-resources), resolving the value in routes/provider components, or using the references API.

An example of using the hasMany reference API:

// get the synchronous "ManyArray" value for the asynchronous "friends" relationship.
// note, this will return `null` if the relationship has not been loaded yet
const value = person.hasMany('friends').value();

// to get just the list of related IDs
const ids = person.hasMany('friends').ids();

References participate in autotracking and getters/cached getters etc. which consume them will recompute if the value changes.

§ Deprecate Promise Proxies

until: 5.0
id: ember-data:deprecate-promise-proxies

Additional Reading: RFC#846 Deprecate Proxies

Deprecates using the proxy object/proxy array capabilities of values returned from:

  • store.findRecord
  • store.findAll
  • store.query
  • store.queryRecord
  • record.save
  • recordArray.save
  • recordArray.update

These methods will now return a native Promise that resolves with the value.

Note that this does not deprecate the proxy behaviors of PromiseBelongsTo. See RFC for reasoning. The opportunity should still be taken if available to stop using these proxy behaviors; however, this class will remain until import Model from '@ember-data/model'; is deprecated more broadly.

§ Deprecate V1 Cache

until: 5.0
id: ember-data:deprecate-v1-cache

Deprecates instantiating a non-singleton cache via store.createRecordDataFor in favor of a singleton-cache via store.createCache.

Most applications should not encounter this deprecation, but if you do it means that an addon you are using is likely using an unsupported cache implementation.

The implementation will need to update to the V2 Cache API and be integrated via the createCache hook.

§ Deprecate V1 cache Store Apis

until: 5.0
id: ember-data:deprecate-v1cache-store-apis

Deprecates various methods on the store and store-cache-wrapper that were specific to the v1 cache.

Most applications should not encounter this deprecation, but if you do it means that an addon you are using is likely using these methods as part of having implemented its own cache.

The implementation will need to update to the V2 Cache API equivalent method as detailed in the deprecation method. Generally this means the implementation needs to be more broadly reworked to use the newer V2.1 Cache API.

§ No A With Array Like

until: 5.0
id: ember-data:no-a-with-array-like

Deprecates calling A() when an EmberData ArrayLike class is detected. This deprecation may not always trigger due to complexities in ember-source versions and the use (or disabling) of prototype extensions.

To fix, use the native JavaScript array methods instead of the EmberArray methods and refrain from wrapping the array in A().

Note that some computed property macros may themselves utilize A(), in which scenario the computed properties need to be upgraded to Ember Octane syntax.

For instance, instead of:

A([]);

Use:

[];

§ Non Explicit Relationships

until: 5.0
id: ember-data:non-explicit-relationships

Deprecates when polymorphic relationships are detected via inheritance or mixins and no polymorphic relationship configuration has been setup.

For further reading please review RFC#793 which introduced support for explicit relationship polymorphism without mixins or inheritance.

You may still use mixins and inheritance to setup your polymorphism; however, the class structure is no longer what drives the design. Instead polymorphism is "traits" based or "structural": so long as each model which can satisfy the polymorphic relationship defines the inverse in the same way they work.

Notably: inverse: null relationships can receive any type as a record with no additional configuration at all.

Example Polymorphic Relationship Configuration:

// polymorphic relationship
class Tag extends Model {
  @hasMany('taggable', { async: false, polymorphic: true, inverse: 'tags' })
  tagged;
}

// an inverse concrete relationship (e.g. satisfies "taggable")
class Post extends Model {
  @hasMany('tag', { async: false, inverse: 'tagged', as: 'taggable' }) tags;
}

Deprecations Added in 4.12

§ Deprecate Instantiate Record Args

until: 5.0
id: ember-data:deprecate-instantiate-record-args

Deprecates using the former 3rd and 4th arguments to Store.instantiateRecord which are now available as properties on the store.

Before:

{
  instantiateRecord(identifier, createArgs, recordDataFor, notifications) {
    const cache = recordDataFor(identifier);
  }
}

After:

{
  instantiateRecord(identifier, createArgs) {
     const { cache, notifications } = this;
  }
}