Skip to content

Commit

Permalink
add allow_wildcard configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
Borzik committed Oct 25, 2019
1 parent 5ce94fd commit f107b18
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Breaking changes:

Features:

- [#2362](https://github.com/rails-api/active_model_serializers/pull/2362) Add `allow_wildcard` configuration option (@Borzik)

Fixes:

- [#2344](https://github.com/rails-api/active_model_serializers/pull/2344) Fixes #2341 introduced since #2223 (@wasifhossain)
Expand Down
12 changes: 12 additions & 0 deletions docs/general/configuration_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ What relationships to serialize by default. Default: `'*'`, which includes one
objects. See [includes](adapters.md#included) for more info.


##### allow_wildcard

Enable wildcard `include` directives (`*`, `**`).

Possible values:

- `true` (default)
- `false`

When `false`, nested associations to be included must be explicitly specified. Note: this will override default_includes configuration as `*` include will no longer be accepted.


##### serializer_lookup_chain

Configures how serializers are searched for. By default, the lookup chain is
Expand Down
3 changes: 2 additions & 1 deletion lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def self.include_directive_from_options(options)
if options[:include_directive]
options[:include_directive]
elsif options[:include]
JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: config.allow_wildcard)
else
ActiveModelSerializers.default_include_directive
end
Expand Down Expand Up @@ -135,6 +135,7 @@ def config.array_serializer
end

config.default_includes = '*'
config.allow_wildcard = true
config.adapter = :attributes
config.key_transform = nil
config.jsonapi_pagination_links_enabled = true
Expand Down
2 changes: 1 addition & 1 deletion lib/active_model_serializers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def self.location_of_caller
# Memoized default include directive
# @return [JSONAPI::IncludeDirective]
def self.default_include_directive
@default_include_directive ||= JSONAPI::IncludeDirective.new(config.default_includes, allow_wildcard: true)
@default_include_directive ||= JSONAPI::IncludeDirective.new(config.default_includes, allow_wildcard: config.allow_wildcard)
end

def self.silence_warnings
Expand Down
4 changes: 2 additions & 2 deletions lib/active_model_serializers/adapter/json_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def self.fragment_cache(cached_hash, non_cached_hash, root = true)

def initialize(serializer, options = {})
super
@include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
@include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: ActiveModelSerializers.config.allow_wildcard)
@fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
end

Expand Down Expand Up @@ -452,7 +452,7 @@ def data_for(serializer, include_slice)
def relationships_for(serializer, requested_associations, include_slice)
include_directive = JSONAPI::IncludeDirective.new(
requested_associations,
allow_wildcard: true
allow_wildcard: ActiveModelSerializers.config.allow_wildcard
)
serializer.associations(include_directive, include_slice).each_with_object({}) do |association, hash|
hash[association.key] = Relationship.new(serializer, instance_options, association).as_json
Expand Down
78 changes: 78 additions & 0 deletions test/action_controller/json/include_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class IncludeTest < ActionController::TestCase
INCLUDE_STRING = 'posts.comments'.freeze
INCLUDE_HASH = { posts: :comments }.freeze
DEEP_INCLUDE = 'posts.comments.author'.freeze
WILDCARD_INCLUDE = '*'.freeze
DEEP_WILDCARD_INCLUDE = '**'.freeze

class IncludeTestController < ActionController::Base
def setup_data
Expand Down Expand Up @@ -57,6 +59,16 @@ def render_resource_with_deep_include
render json: @author, include: DEEP_INCLUDE, adapter: :json
end

def render_resource_with_wildcard_include
setup_data
render json: @author, include: WILDCARD_INCLUDE, adapter: :json
end

def render_resource_with_deep_wildcard_include
setup_data
render json: @author, include: DEEP_WILDCARD_INCLUDE, adapter: :json
end

def render_without_recursive_relationships
# testing recursive includes ('**') can't have any cycles in the
# relationships, or we enter an infinite loop.
Expand Down Expand Up @@ -114,6 +126,48 @@ def test_render_resource_with_deep_include
assert_equal(expected_deep_include_response, response)
end

def test_render_resource_with_wildcard_include
get :render_resource_with_wildcard_include

response = JSON.parse(@response.body)

assert_equal(expected_wildcard_include_response, response)
end

def test_render_resource_with_wildcard_include_with_wildcards_disabled
with_wildcards_disabled do
get :render_resource_with_wildcard_include
end

expected = {
'author' => {
'id' => 1,
'name' => 'Steve K.'
}
}

response = JSON.parse(@response.body)

assert_equal(expected, response)
end

def test_render_resource_with_deep_wildcard_include_with_wildcards_disabled
with_wildcards_disabled do
get :render_resource_with_deep_wildcard_include
end

expected = {
'author' => {
'id' => 1,
'name' => 'Steve K.'
}
}

response = JSON.parse(@response.body)

assert_equal(expected, response)
end

def test_render_with_empty_default_includes
with_default_includes '' do
get :render_without_include
Expand Down Expand Up @@ -176,6 +230,22 @@ def test_render_with_includes_overrides_default_includes

private

def expected_wildcard_include_response
{
'author' => {
'id' => 1,
'name' => 'Steve K.',
'posts' => [
{
'id' => 42, 'title' => 'New Post', 'body' => 'Body'
}
],
'roles' => [],
'bio' => {}
}
}
end

def expected_include_response
{
'author' => {
Expand Down Expand Up @@ -238,6 +308,14 @@ def with_default_includes(include_directive)
clear_include_directive_cache
end

def with_wildcards_disabled
original = ActiveModelSerializers.config.allow_wildcard
ActiveModelSerializers.config.allow_wildcard = false
yield
ensure
ActiveModelSerializers.config.allow_wildcard = original
end

def clear_include_directive_cache
ActiveModelSerializers
.instance_variable_set(:@default_include_directive, nil)
Expand Down
17 changes: 17 additions & 0 deletions test/action_controller/json_api/linked_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,23 @@ def test_render_resource_with_nested_has_many_include
assert_equal expected_linked, response['included']
end

def test_render_resource_with_nested_has_many_include_with_wildcards_disabled
ActiveModel::Serializer.config.allow_wildcard = false
get '/render_resource_with_nested_has_many_include_wildcard'
ActiveModel::Serializer.config.allow_wildcard = true
response = JSON.parse(@response.body)
expected_linked = [
{
'id' => '1',
'type' => 'authors',
'attributes' => {
'name' => 'Steve K.'
}
}
]
assert_equal expected_linked, response['included']
end

def test_render_resource_with_include_of_custom_key_by_original
get '/render_resource_with_include_of_custom_key_by_original'
response = JSON.parse(@response.body)
Expand Down

0 comments on commit f107b18

Please sign in to comment.