Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unable to serialize unpersisted records #2132

Closed
InteNs opened this issue May 14, 2017 · 13 comments
Closed

unable to serialize unpersisted records #2132

InteNs opened this issue May 14, 2017 · 13 comments

Comments

@InteNs
Copy link

InteNs commented May 14, 2017

Expected behavior vs actual behavior

expected:
ActiveModelSerializer::SerializableResource.new(FactoryGirl.build(:some_object).as_json


"{ 
  "data": {
    "type": "some-objects",
    "id": null,                            #or just not there entirely
    "attributes": { /// }
  }
}"           
actual:
ActiveModelSerializer::SerializableResource.new(FactoryGirl.build(:some_object).as_json


"{ "data": null }"

Steps to reproduce

serialize an activerecord object that doesn't have an id yet
in 0.10.5 it behaves as expected
in 0.10.6 it returns data null

Environment

ActiveModelSerializers Version: 0.10.6

Output of ruby -e "puts RUBY_DESCRIPTION":
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin16]

OS Type & Version: osx 10.12.4

Integrated application and version: rails 4.2

Additonal helpful information

This functionality was introduced in #2119 specifically here
and someone else already complained about it in #2126

I also use this functionality to test my controller endpoints, serializing non-saved objects in order to test POST and PATCH requests.

Why was this functionality added, and is there another way to serialize non-persisted records via json-api adapter?

@morhekil
Copy link

+1 to the problem above - we just ran into the same issue after a seemingly minor update.

We're actually relying on the previous behaviour by emitting partially bootstrapped records from the API where they are pre-populated with basic data, but don't have an ID set as they aren't persisted yet, so this is a breaking change for us.

@bf4
Copy link
Member

bf4 commented May 15, 2017

@morhekil @InteNs So, even though that payload is invalid JSON:API, we should still allow you to create it. Either of you want to help with a pull request?

@morhekil
Copy link

@bf4 I've been reading up on JSON:API docs today after this, and I'm not convinced that the behaviour we were relying on is the correct one - I agree with the change itself, and that per JSON:API spec record's id must not be nil for tje record to a representable resource.

On the other hand, I find the current behaviour of the serializer when it just silently replaces a record with a null quite frustrating, as it doesn't actually provide me with a feedback. Should it maybe throw an exception in this case instead, and if user really wants to render nil - they can handle the exception and do it anyway?

Also, I believe that a lot of this confusion came from this change being introduced in a patch-level release - it has already been pointed out in #2126, but it really would be a non-issue if it was done as a major release with properly announced backward-incompatible changes.

@bf4
Copy link
Member

bf4 commented May 15, 2017

Should it maybe throw an exception in this case instead, and if user really wants to render nil - they can handle the exception and do it anyway?

I think that's a good thing to be user-configurable since not everyone would want the same behavior or even both in prod and dev.

Also, I believe that a lot of this confusion came from this change being introduced in a patch-level release

I didn't know that this was breaking anything, otherwise I wouldn't have released it ;) There are a lot of people that use AMS in ways that aren't all tested or intended, so these kinds of things happen. I use AMS myself and it didn't break anything for me... So, now that we've identified this change in expected behavior, let's work to fix it :) Which includes, what should the behavior actually be?

@yoda
Copy link

yoda commented May 26, 2017

Have the same issue with this, because we depend on extra ncrud where n is new that produce the state of the object with default values set however because the object is not persisted yet it has no id which invalidates the jsonapi spec. A dodgey way is to set an invalid id but something better than that would be good, any suggestions?

@InteNs
Copy link
Author

InteNs commented May 26, 2017

i would like to see an serializer option like new_record: true or something similar that would allow non persisted records to be serialized without id

@beet
Copy link

beet commented Jun 22, 2017

We just got a nasty surprise from this update as well, but reading the comments thread I suppose we were misusing the JSON API spec.

Our use-case was creating records from a form via AJAX. When validation errors prevented the object from being created, we returned it with the validation errors in an attribute which the UI fetched out and presented to the user.

With the update from Rails 5.1.0 to 5.1.1, it began returning { "data": null } instead, which breaks the error handler and prevents the user from seeing their validation error messages.

Maybe instead of silently rendering { "data": null } it could instead provide the data as meta information?

Persisted record:

{
  "data": {
    "id": "123",
    "type:" "users",
    "attributes:" {
      // ...
    }
  }
}

Not persisted record:

{
  "meta": {
    "data": {
      "id": null,
      "type:" "users",
      "attributes:" {
        // ...
      }
    }
  }
}

Could have a crack at a PR if it seems like a good solution.

@xn
Copy link
Contributor

xn commented Aug 29, 2017

This bit me hard and wrecked my test suite. My use case:

let(:user_attributes) { FactoryGirl.build(:user) }
put "/v1/users/#{user.id}", params: ActiveModelSerializers::Adapter::JsonApi.new(UserSerializer.new(user_attributes)).serializable_hash

Is there some better way to do this?

@xn
Copy link
Contributor

xn commented Aug 29, 2017

From the spec:
Creating Resources
A resource can be created by sending a POST request to a URL that represents a collection of resources. The request MUST include a single resource object as primary data. The resource object MUST contain at least a type member.

@xn
Copy link
Contributor

xn commented Aug 29, 2017

#2180

@Genkilabs
Copy link

+1 Being able to transmit non-persisted / recently initialized data is IMO a valid use case.

@gambala
Copy link

gambala commented Sep 17, 2017

My (dirty but) workaround for now — set an id of the record to 0 or -1 and serialize it.

{
  "data": {
    "type": "some-objects",
    "id": "0",
    "attributes": { ... }
  }
}

@bf4
Copy link
Member

bf4 commented Nov 2, 2017

Fixed by #2216

@bf4 bf4 closed this as completed Nov 2, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants