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 support for wildcards in nested includes #1158

Merged
merged 1 commit into from
Sep 21, 2015

Conversation

beauby
Copy link
Contributor

@beauby beauby commented Sep 16, 2015

Adds support for the following:

render json: posts, include: 'author, comments.*'
# includes the author, the comments, and all of the comments' related resources

render json: posts, include: [:author, comments: '*']
# same, with the array format

render json: posts, include: 'author, comments.**'
# includes the author, the comments, and all of the comments' related resources, and their related resources, etc.

Note that the wildcard (*) only expands one level, so you can chain them if you want more and keep control over the depth of the inclusion ('comments.*.*' for instance), or you can specify a double wildcard (**) if you want infinite expansion.

@beauby beauby force-pushed the includes-wildcard branch 3 times, most recently from f0bf341 to 883a684 Compare September 16, 2015 07:05
@@ -119,10 +119,26 @@ def relationships_for(serializer)
Hash[serializer.associations.map { |association| [association.key, { data: relationship_value_for(association.serializer, association.options) }] }]
end

def expand_includes(includes, associations)
Copy link
Contributor

Choose a reason for hiding this comment

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

can you write some yardoc about what this method does, and some example inputs and outputs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do!

@beauby beauby changed the title Add support for wildcards in nested includes for JsonApi Add support for wildcards in nested includes Sep 16, 2015
@beauby
Copy link
Contributor Author

beauby commented Sep 16, 2015

Now also works with (Flatten)Json adapters.

# and corresponding inclusion hashes.
# @param [Hash] includes
# @return [Array] an array of pairs [association, include_hash] for matching associations
def expand_includes(includes)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this format be different from the other format?
I'd prefer it to be the same, hash of hashes

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 one has a different purpose. I'm not happy with the name of this method, because what it really does is lookup each included association and returns the corresponding Association and include hash. It just happens to expand stuff because at this stage we can't avoid it anymore.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Having this function just return a hash would force an other lookup of the associations down the road.

Copy link
Contributor

Choose a reason for hiding this comment

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

gotchya

association.options[:virtual_value]
elsif association.serializer && association.serializer.object
FlattenJson.new(association.serializer,
association.options.merge(include: assoc_includes))
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 line gives a rubocop warning about aligning method parameters that span multiple lines, although I believe the indentation is right here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Have the first param on the next line, indented two spaces from the start of the F?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

could be a bug in rubocop. I don't think it validates itself against the style guide and diverges at times

Copy link
Member

Choose a reason for hiding this comment

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

but there's definitley too much going on in that block

@beauby beauby force-pushed the includes-wildcard branch 9 times, most recently from 52e5433 to 0de720d Compare September 21, 2015 00:27
@@ -2,6 +2,11 @@ module ActiveModel
class Serializer
module Adapter
class Attributes < Base
def initialize(serializer, options = {})
super
@include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(options[:include] || '*')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

By default, include all the toplevel specified association (current behavior).

Copy link
Contributor

Choose a reason for hiding this comment

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

should the default value be move to the method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, because we want the flexibility to have different default values per adapter. For instance, the JsonApi adapter defaults to none (since the relationship objects themselves will be serialized anyways, we don't want to enforce the related resources to be included in the answer unless specified by the user).

Copy link
Member

Choose a reason for hiding this comment

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

Does this need to be in the initializer? Does it need to be eager evaluated? Also, you could

def initialize(*)
  super
  # use whatever the super method did

which is more resistant to changes in method signature or whatever

#
# @param [String] included
# @return [IncludeTree]
#
Copy link
Contributor

Choose a reason for hiding this comment

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

yay documentation!!!

but I think @return is supposed to be the last line of the comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure, there are many places in the current code base where the format is as above. I don't mind changing it, once we make a consistent choice for the future.

Copy link
Member

Choose a reason for hiding this comment

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

Long class << self blocks are hard to read. Better to just use def self.method_name.

I only did it in Adapter because I was class << Adapter which is easier to read than def Adapter.whatever and a little less surprising, but also I was intending to get rid of it eventually.

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 tend to agree, although it's a pattern that is wildly used within rails. What do you think? I don't mind changing it.

Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer def self.method_name unless you feel it's clearer or better otherwise

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks good to me, updating immediately.

Copy link
Member

Choose a reason for hiding this comment

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

Also, some of these styles will need to be autocorrected if we merge #1183

Copy link
Member

Choose a reason for hiding this comment

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

I don't think Helper is a good name, but I wanted to just get the idea across :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I thought of Parsing instead, what do you think?

Copy link
Member

Choose a reason for hiding this comment

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

or Transformation.. but since it's internal so far, I'm not too concerned

@bf4
Copy link
Member

bf4 commented Sep 21, 2015

I think this PR would benefit from including documentation of usage as well as caveats. I see this feature as a major bug report attractor, so would be great to just point to docs which describe what it can't be guaranteed to do well, or performantly.

@beauby
Copy link
Contributor Author

beauby commented Sep 21, 2015

My intent was to build it first for internal usage (the wildcards themselves make the nested serializers much easier to write), and document it in a subsequent PR.

@bf4
Copy link
Member

bf4 commented Sep 21, 2015

@beauby Ok with me if you're doing it in steps like that. I haven't had the issue this PR is solving, so I'm not a 'domain' expert on what's best for AMS in this regard

@@ -1,11 +1,11 @@
require 'thread_safe'
require 'active_model/serializer/adapter'
require 'active_model/serializer/array_serializer'
require 'active_model/serializer/include_tree'
require 'active_model/serializer/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.

It has to be before associations, because we use it in there.

when @hash.key?(:**)
self.class.new(:** => {})
else
nil
Copy link
Member

Choose a reason for hiding this comment

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

@beauby You're saying Rubocop didn't like this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@joaomdmoura
Copy link
Member

Nice! 👍

@bf4 bf4 deleted the includes-wildcard branch October 9, 2015 06:42
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.

4 participants