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

Add regression test for fields in JSON/Attributes adapter #1285

Closed
wants to merge 1 commit into from
Closed

Add regression test for fields in JSON/Attributes adapter #1285

wants to merge 1 commit into from

Conversation

vasilakisfil
Copy link
Contributor

Regression test showing how fields fails when there are associations

def test_fields_with_no_associations_include_option
serializer = ArraySerializer.new([@first_post, @second_post])
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
actual = adapter.serializable_hash(fields: [:id])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The option should not be passed to serializable_hash but to the adapter's constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can fix it. But I should inform you that fields are working out of the box because there is a bug here: https://github.com/rails-api/active_model_serializers/blob/master/lib/action_controller/serialization.rb#L50-L51

and not because the adapter's constructor passes the fields option to the serializer. (the adapter's options are in instance_options whereas the serializer options are in options all Attributes methods)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, you should replace those 3 lines with:

actual = ActiveModel::SerializableResource.new([@first_post, @second_post], adapter: :json, fields: [:id])

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I agree, but it's not working even in master, I will send a regression test now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actual = ActiveModel::SerializableResource.new([@first_post, @second_post], adapter: :json, fields: [:id])

@vasilakisfil plz amend per @beauby

# maybe some setup to explain
actual = ActiveModel::SerializableResource.new([@first_post, @second_post], adapter: :json, fields: [:id]).as_json
expected = { posts: [{id: 1}, {id: 2}] }
assert_equal(actual, expected)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I thought fields was JSON API specific. I'm not against adding some of the JSON API semantics to the JSON adapter, though

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bf4 Well currently the Json adapter does support a lesser version of the fields option (namely it allows to specify the attributes but just for the primary data). Support is broken though.

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

So, for the record:

  --- expected
  +++ actual
  @@ -1 +1 @@
  -{:posts=>[{:id=>1}, {:id=>2}]}
  +{:posts=>[{:id=>1, :comments=>[], :blog=>{:id=>999}, :author=>{:id=>1}}, {:id=>2, :comments=>[], :blog=>{:id=>999}, :author=>{:id=>1}}]}

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

It is expected that the (first-level) associations be included, as the fields option deals only with attributes. What's possibly not expected is that those associations only get their id serialized, and no other attribute.

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

So there are two issues here:

  1. currently the Attributes/Json adapter only support specifying fields for the primary resource (on paper at least). We could discuss about making it work with an IncludeTree as well.
  2. the fields option should not be passed to recursive calls to build the related resources (and this should happen here)

@vasilakisfil
Copy link
Contributor Author

@beauby see #1286
Regarding fields for associations I am a big advocate of this since it's very little amount of work compared to what we gain.

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

@vasilakisfil Currently, associations are handled through the include option and attributes through the fields option. Mixing both will prevent people from just constraining the associations.

@vasilakisfil
Copy link
Contributor Author

@beauby you can still filter associations based on includes. Fields on association is optional meaning that if you don't provide any fields for an association it won't apply and thus it will render all attributes of the associations (like it is now).

I want and I believe that you should be able to select in the JSON/Attributes adapters specific fields of an association. Do you have something else to suggest ?

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

I'm not convinced. Could you show me some use cases?

@vasilakisfil
Copy link
Contributor Author

@beauby the same use cases that apply on filtering the attributes of the main association, the same apply on filtering the attributes of an association. Am I missing something ?

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

Sure sure, but In what situation would you really need to control that at the adapter level? You can already design your serializers in such a way that it covers most use cases I think. Do you have an (real-world) example where this feature would be needed?

@vasilakisfil
Copy link
Contributor Author

I thought we had agreed that we need that in the constructor level in another thread #1141 (comment)

Permissions is one reason: I don't want to have multiple serializers for every role, neither do I want to have the authorization logic in the serializers.
Imitating Facebook's GraphQL is another reason. Let the client decide.

@vasilakisfil
Copy link
Contributor Author

Plus, isn't that possible currently in the JSONAPI adapter?

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

I was talking about JsonApi in that thread. The reason I'm not convinced is because the Json/Attributes adapters are clearly not good choices when you start having complex needs, and I think it's better if users realize this sooner than later.

@vasilakisfil
Copy link
Contributor Author

I disagree with that but OK. So should I continue working on that PR or should I start creating my own adapter ?

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

Currently in the JsonApi adapter we support only the "array syntax", that is {type1: [:attr1, :attr2, ...], type2: [...], type3: [...]}. There is no notion of nesting here, just for each type of resource which attributes we want to include.

@beauby
Copy link
Contributor

beauby commented Oct 20, 2015

@vasilakisfil This decision is not final, let's hear other people's thoughts (cc @joaomdmoura @bf4 @NullVoxPopuli)

@NullVoxPopuli
Copy link
Contributor

I think fields shouldn't touch associations -- that (I believe) would cause a lot of confusion around the choice of the word fields and with existing functionality.

maybe the same thing could be accomplished by also specifying the include option?

render json: @objects, fields: [:id], include: ''

@vasilakisfil
Copy link
Contributor Author

fields don't touch associations unless you have one under includes. I don't
think it's possible what you said.

I think the main issue here is: do we want filtering the attributes on
association level or allow only on the main resource?
On Oct 20, 2015 10:12 PM, "L. Preston Sego III" [email protected]
wrote:

I think fields shouldn't touch associations -- that (I believe) would
cause a lot of confusion around the choice of the word fields and with
existing functionality.

maybe the same thing could be accomplished by also specifying the include
option?

render json: @objects, fields: [:id], include: ''


Reply to this email directly or view it on GitHub
#1285 (comment)
.

@@ -85,6 +85,20 @@ def test_include_option

assert_equal(expected, actual)
end

def test_fields_with_no_associations_include_option
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(test name out of date)

@NullVoxPopuli
Copy link
Contributor

ah, I see what you're saying.

I would be in favor of mimicing what json api is currently doing.

Add regression test for fields in JSON/Attributes adapter

fix regression tests
@bf4
Copy link
Member

bf4 commented Mar 13, 2016

@NullVoxPopuli @vasilakisfil @beauby If I understand the JSON API spec correctly, fields act on resources in the response. includes just adds resources to the response. As it reads:

Given an 'article' of type 'articles" that has an 'author' of type 'people':

Request with fields parameter:

GET /articles?include=author&fields[articles]=title,body,author&fields[people]=name
Here we want articles objects to have fields title, body and author only and people objects to have name field only [emphasis mine -BF].

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!",
      "body": "The shortest article. Ever."
    },
    "relationships": {
      "author": {
        "data": {"id": "42", "type": "people"}
      }
    }
  }],
  "included": [
    {
      "type": "people",
      "id": "42",
      "attributes": {
        "name": "John"
      }
    }
  ]
}

Pay attention to the fact that you have to add a relationship name both in include and fields (since relationships are fields too) [Emphasis mine -BF]

@remear
Copy link
Member

remear commented Mar 28, 2016

@rails-api/ams Are we still interested in this?

@bf4
Copy link
Member

bf4 commented Mar 29, 2016

@remear Yes

@remear
Copy link
Member

remear commented Sep 16, 2016

Closing due to inactivity

@remear remear closed this Sep 16, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants