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

Fix fields option to restrict relationships as well. #1297

Merged
merged 2 commits into from
Oct 26, 2015

Conversation

beauby
Copy link
Contributor

@beauby beauby commented Oct 24, 2015

The current implementation breaks the JSON API spec in the way it handles sparse fieldsets, since the definition of fields is:

A resource object's attributes and its relationships are collectively called its "fields".

@@ -174,7 +174,10 @@ def relationship_value_for(serializer, options = {})
end

def relationships_for(serializer)
serializer.associations.each_with_object({}) do |association, hash|
resource_type = resource_identifier_type_for(serializer)
requested_associations = fieldset.try(:fields_for, resource_type) || '*'
Copy link
Contributor

Choose a reason for hiding this comment

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

in what situation does a fieldset not have fields_for?

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess, I'd like some docs here explaining why this is happening :-)
I'll be ok with merging once that's done. :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When fieldset is not initialized (which currently happens when the fields option is not provided).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Docs explaining why what is happening?

Copy link
Contributor

Choose a reason for hiding this comment

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

the situation you just described with fieldset.
It's important to have docs like this when someone new starts working on the json api adapter.

Copy link
Contributor

Choose a reason for hiding this comment

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

also, that's not an excuse to get out of writing docs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Code comments are not docs in my opinion. Maybe we're not talking about the same thing?

Copy link
Contributor

Choose a reason for hiding this comment

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

perhaps.
I'm not meaning to write something that just anyone would look at. but a reminder of what is happening in the code, possibly the scenarios in which certain control flows are followed - so that even the author of the code can have an easier time re-familiarizing with the code 1+ years from when the code was written.
node of that is intended to be in the public documentation that would end up on ruby-doc.org or anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Then I still disagree. Code that needs explanations is just bad code in my opinion. If you think this bit is obscure, then I'd rather we work to make it less obscure than write a comment to explain it.

Copy link
Member

Choose a reason for hiding this comment

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

Um.. I don't understand the change from the code :)

@@ -21,7 +21,7 @@ def fields_for(type)

def parsed_fields
if raw_fields.is_a?(Hash)
raw_fields.inject({}) { |h, (k, v)| h[k.to_sym] = v.map(&:to_sym); h }
raw_fields.each_with_object({}) { |(k, v), h| h[k.to_sym] = v.map(&:to_sym) }
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This (isomorphic) change is not necessary for this PR, but it makes the code slightly cleaner.

NullVoxPopuli added a commit that referenced this pull request Oct 26, 2015
Fix `fields` option to restrict relationships as well.
@NullVoxPopuli NullVoxPopuli merged commit 55ff9ac into rails-api:master Oct 26, 2015
@bf4
Copy link
Member

bf4 commented Oct 26, 2015

@beauby @NullVoxPopuli can you help me understand why the order of the fieldset was changed? Also, for a bit I thought the :fields option was deleted due to the inlining of the conditional, fwiw.

-          fields = options.delete(:fields)
-          if fields
-            @fieldset = ActiveModel::Serializer::Fieldset.new(fields)
-          else
-            @fieldset = options[:fieldset]
-          end
+          @fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))

Is really the same as

-          fields = options.delete(:fields)
-          if fields
-            @fieldset = ActiveModel::Serializer::Fieldset.new(fields)
-          else
-            @fieldset = options[:fieldset]
-          end
+         @fieldset = options[:fieldset]
+         if @fieldset.nil?
+           fields = options.delete(:fields))
+           @fieldset = ActiveModel::Serializer::Fieldset.new(fields || {}) # where the fieldset initializer was modified as paraphrased here
+          end

resource_type = resource_identifier_type_for(serializer)
requested_associations = fieldset.fields_for(resource_type) || '*'
include_tree = IncludeTree.from_include_args(requested_associations)
serializer.associations(include_tree).each_with_object({}) do |association, hash|
Copy link
Member

Choose a reason for hiding this comment

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

In words, what does this diff do?

-          serializer.associations.each_with_object({}) do |association, hash|
+          resource_type = resource_identifier_type_for(serializer)
+          requested_associations = fieldset.fields_for(resource_type) || '*'
+          include_tree = IncludeTree.from_include_args(requested_associations)
+          serializer.associations(include_tree).each_with_object({}) do |association, hash|

It's supposed to somehow remove associations somehow?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It filters out associations not present in the fieldset of the resource (unless no fieldset has been provided for that resource).

Copy link
Member

Choose a reason for hiding this comment

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

maybe it's just the method and variable names. I can be pretty literal-minded and it looks like whereas before we would iterate over the associations, now we ask the serializer what it's type ask the fieldset for its fields, or use *, which guess means ALL, the include_tree is something that is passed to associations?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Exactly. The IncludeTree is probably not a perfect name. It is basically a structure that describes a labelled tree in such a way that you can query it using wildcards.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

serializer.associations(include_tree) this filters associations

Copy link
Contributor

Choose a reason for hiding this comment

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

@beauby I guess this means that an explanation needs to be in code comments. :-)

@bf4
Copy link
Member

bf4 commented Oct 26, 2015

Would like to promote discussion of optimizing code to not make me think: #1297 (comment) 😄

@beauby
Copy link
Contributor Author

beauby commented Oct 26, 2015

@bf4 Any suggestion welcome.

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.

None yet

3 participants