Excluding attributes sent to the server

I have a model that, for business reasons, has an attribute that contains a value from a global counter. This attribute needs to be displayed.

Oh, some background: Ember 2.18 + Rails 5.2 API back-end w/jsonapi-resources gem. On the Rails side said Resource has this attribute removed from the list of createable & updateable fields lists.

The backend is configured to not expect it in the attributes hash when creating or updating said model.

Is there a way to exclude this attribute when saving/updating the model?

Thank you for your time.

If I understand you correctly it looks like a job for a custom serializer where you should simply delete the attribute before sending to the backend (exclude from serialization). Take a look at: Customizing Serializers - Ember Data - Ember Guides

1 Like

Yeah, here’s how to customize a serializer so it doesn’t try to save the title attribute:

import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
  serialize() {
    let payload = this._super(...arguments);
    delete payload.data.attributes.title;
    return payload;
  }
});

And for completeness, the converse (adding a field that the server didn’t really send):

import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
  normalizeResponse(store, modelClass, payload, id, requestType) {
    payload.data.attributes.title = "Fake Title";
    return this._super(store, modelClass, payload, id, requestType);
  }
});

Together, this is 100% of what you really need to know about serializers. Everything else is just shorthands for doing what you could do manually in these two methods.

Curious onlookers might think “but what about the other kinds of serializers, like RESTSerializer?”. Nope, I don’t think there’s any reason to ever use them. The reason I think that is that

  • internally, everything in Ember Data already converts to JSON:API. This is a good thing, because it means you have a clear spec for the shape of the data.
  • you can write your serializers just like the ones above to convert between JSON:API (which is easy to learn and understand because it’s a crisp, thorough spec) and whatever home-grown API your server has (which you presumably also understand).
4 Likes

Thanks @PoslinskiNet and @ef4 for your replies. It looks like this is exactly what I’m looking for.

1 Like

@melriffe I would simply do:

import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
  attrs: {
    title: {
      serialize: false
    }
  }
});

3 Likes

This is also correct. I didn’t pick it for my answer because I personally think the adapter & serializer API errs on the side of being too broad and customizable, making it harder to learn and remember. But it’s certainly fair game to keep using all those other methods and properties, they’re public API.

2 Likes

I have something similar in one of my projects that had couple of attributes, across different models.

import DS from 'ember-data';

export default DS.JSONAPISerializer.extend({
  serializeAttribute(snapshot, json, key, attribute) {
    if (!attribute.options.readOnly) {
      this._super(...arguments);
    }
  }
});

Having this in my serializer allows me to specify attributes as read-only, and those are not send back to the server.

import Model from 'ember-data/model';
import attr from 'ember-data/attr';

export default Model.extend({
  updatedBy: attr('string', { readOnly: true })
});
6 Likes

Is there any way to include data when creating the object but not when patching it? There are several create only fields and there may be patch only fields as well

Hi,

Is it possible to do it with DS.RESTSerializer ? Also, is it possible to specify the model because I might have same attributes name is some model but I still want to send it, depends on the model

Thanks !

Hi @Dylan_Dinh,

Per some of the discussion above there are many (perhaps to a fault) different ways to accomplish a given thing with the serializer/adapter APIs, and all of the ones discussed above should work with RestSerializer. For example the serializeAttribute method.

If you want different behavior per-model the easiest way to do that is to specify a serializer just for one model (by simply naming the serializer the same as the model, e.g. for model “post” you’d call your serializer “post.js”). Typically the easiest way to structure this would be to have an application serializer that defines application level behavior, and then per-model serializers that extend the application serializer when needed.