active_model_serializers 0.10.0 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -4
- data/.travis.yml +9 -1
- data/CHANGELOG.md +81 -2
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +5 -2
- data/README.md +24 -24
- data/Rakefile +3 -3
- data/active_model_serializers.gemspec +20 -24
- data/docs/ARCHITECTURE.md +6 -7
- data/docs/README.md +2 -0
- data/docs/general/adapters.md +4 -2
- data/docs/general/caching.md +7 -1
- data/docs/general/configuration_options.md +70 -1
- data/docs/general/deserialization.md +1 -1
- data/docs/general/fields.md +31 -0
- data/docs/general/rendering.md +42 -3
- data/docs/general/serializers.md +97 -8
- data/docs/howto/add_pagination_links.md +4 -5
- data/docs/howto/add_relationship_links.md +137 -0
- data/docs/howto/add_root_key.md +4 -0
- data/docs/howto/grape_integration.md +42 -0
- data/docs/howto/outside_controller_use.md +9 -2
- data/docs/howto/passing_arbitrary_options.md +2 -2
- data/docs/howto/test.md +2 -0
- data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
- data/docs/integrations/ember-and-json-api.md +64 -32
- data/docs/jsonapi/schema.md +1 -1
- data/lib/action_controller/serialization.rb +13 -3
- data/lib/active_model/serializer/adapter/base.rb +2 -0
- data/lib/active_model/serializer/array_serializer.rb +8 -5
- data/lib/active_model/serializer/association.rb +19 -4
- data/lib/active_model/serializer/belongs_to_reflection.rb +0 -3
- data/lib/active_model/serializer/collection_serializer.rb +35 -12
- data/lib/active_model/serializer/{associations.rb → concerns/associations.rb} +13 -11
- data/lib/active_model/serializer/{attributes.rb → concerns/attributes.rb} +0 -0
- data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +72 -113
- data/lib/active_model/serializer/{configuration.rb → concerns/configuration.rb} +25 -1
- data/lib/active_model/serializer/{links.rb → concerns/links.rb} +0 -0
- data/lib/active_model/serializer/{meta.rb → concerns/meta.rb} +0 -0
- data/lib/active_model/serializer/{type.rb → concerns/type.rb} +0 -0
- data/lib/active_model/serializer/error_serializer.rb +11 -7
- data/lib/active_model/serializer/errors_serializer.rb +25 -20
- data/lib/active_model/serializer/has_many_reflection.rb +0 -3
- data/lib/active_model/serializer/has_one_reflection.rb +0 -3
- data/lib/active_model/serializer/lint.rb +134 -130
- data/lib/active_model/serializer/reflection.rb +37 -21
- data/lib/active_model/serializer/version.rb +1 -1
- data/lib/active_model/serializer.rb +76 -37
- data/lib/active_model_serializers/adapter/attributes.rb +3 -66
- data/lib/active_model_serializers/adapter/base.rb +38 -38
- data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
- data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +8 -1
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +30 -19
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +23 -9
- data/lib/active_model_serializers/adapter/json_api.rb +44 -43
- data/lib/active_model_serializers/adapter.rb +6 -0
- data/lib/active_model_serializers/deprecate.rb +1 -2
- data/lib/active_model_serializers/deserialization.rb +2 -0
- data/lib/active_model_serializers/key_transform.rb +4 -0
- data/lib/active_model_serializers/lookup_chain.rb +80 -0
- data/lib/active_model_serializers/model.rb +4 -2
- data/lib/active_model_serializers/railtie.rb +3 -1
- data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
- data/lib/active_model_serializers/serializable_resource.rb +6 -5
- data/lib/active_model_serializers/serialization_context.rb +10 -3
- data/lib/active_model_serializers.rb +7 -0
- data/lib/generators/rails/serializer_generator.rb +4 -4
- data/lib/grape/active_model_serializers.rb +7 -5
- data/lib/grape/formatters/active_model_serializers.rb +19 -2
- data/lib/grape/helpers/active_model_serializers.rb +1 -0
- data/test/action_controller/adapter_selector_test.rb +4 -4
- data/test/action_controller/explicit_serializer_test.rb +5 -4
- data/test/action_controller/json/include_test.rb +106 -27
- data/test/action_controller/json_api/errors_test.rb +6 -7
- data/test/action_controller/json_api/fields_test.rb +57 -0
- data/test/action_controller/json_api/linked_test.rb +29 -24
- data/test/action_controller/json_api/pagination_test.rb +19 -19
- data/test/action_controller/json_api/transform_test.rb +3 -3
- data/test/action_controller/lookup_proc_test.rb +49 -0
- data/test/action_controller/namespace_lookup_test.rb +226 -0
- data/test/action_controller/serialization_test.rb +10 -7
- data/test/active_model_serializers/json_pointer_test.rb +15 -13
- data/test/active_model_serializers/key_transform_test.rb +286 -252
- data/test/active_model_serializers/model_test.rb +17 -4
- data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +143 -0
- data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
- data/test/adapter/attributes_test.rb +43 -0
- data/test/adapter/json/collection_test.rb +14 -0
- data/test/adapter/json/transform_test.rb +15 -15
- data/test/adapter/json_api/collection_test.rb +4 -3
- data/test/adapter/json_api/errors_test.rb +17 -19
- data/test/adapter/json_api/fields_test.rb +4 -3
- data/test/adapter/json_api/has_many_test.rb +39 -18
- data/test/adapter/json_api/include_data_if_sideloaded_test.rb +166 -0
- data/test/adapter/json_api/json_api_test.rb +5 -7
- data/test/adapter/json_api/linked_test.rb +33 -12
- data/test/adapter/json_api/links_test.rb +4 -2
- data/test/adapter/json_api/pagination_links_test.rb +35 -8
- data/test/adapter/json_api/relationship_test.rb +309 -73
- data/test/adapter/json_api/resource_identifier_test.rb +27 -2
- data/test/adapter/json_api/resource_meta_test.rb +3 -3
- data/test/adapter/json_api/transform_test.rb +255 -253
- data/test/adapter/json_api/type_test.rb +1 -1
- data/test/adapter/json_test.rb +8 -7
- data/test/adapter/null_test.rb +1 -2
- data/test/adapter/polymorphic_test.rb +5 -5
- data/test/adapter_test.rb +1 -1
- data/test/benchmark/app.rb +1 -1
- data/test/benchmark/benchmarking_support.rb +1 -1
- data/test/benchmark/bm_active_record.rb +81 -0
- data/test/benchmark/bm_adapter.rb +38 -0
- data/test/benchmark/bm_caching.rb +16 -16
- data/test/benchmark/bm_lookup_chain.rb +83 -0
- data/test/benchmark/bm_transform.rb +16 -5
- data/test/benchmark/controllers.rb +16 -17
- data/test/benchmark/fixtures.rb +72 -72
- data/test/cache_test.rb +143 -49
- data/test/collection_serializer_test.rb +3 -3
- data/test/fixtures/poro.rb +52 -48
- data/test/generators/serializer_generator_test.rb +22 -5
- data/test/grape_test.rb +152 -56
- data/test/lint_test.rb +1 -1
- data/test/logger_test.rb +13 -11
- data/test/serializable_resource_test.rb +18 -22
- data/test/serializers/association_macros_test.rb +3 -2
- data/test/serializers/associations_test.rb +107 -32
- data/test/serializers/attribute_test.rb +2 -2
- data/test/serializers/attributes_test.rb +1 -1
- data/test/serializers/fieldset_test.rb +1 -1
- data/test/serializers/meta_test.rb +12 -6
- data/test/serializers/root_test.rb +1 -1
- data/test/serializers/serializer_for_test.rb +6 -4
- data/test/serializers/serializer_for_with_namespace_test.rb +87 -0
- data/test/support/isolated_unit.rb +5 -2
- data/test/support/rails5_shims.rb +8 -2
- data/test/support/rails_app.rb +0 -9
- data/test/support/serialization_testing.rb +23 -5
- data/test/test_helper.rb +1 -0
- metadata +85 -34
- data/.rubocop_todo.yml +0 -167
- data/lib/active_model/serializer/include_tree.rb +0 -111
- data/test/adapter/json_api/relationships_test.rb +0 -199
- data/test/include_tree/from_include_args_test.rb +0 -26
- data/test/include_tree/from_string_test.rb +0 -94
- data/test/include_tree/include_args_to_hash_test.rb +0 -64
@@ -9,7 +9,7 @@ module ActiveModelSerializers
|
|
9
9
|
attr_reader :attributes, :errors
|
10
10
|
|
11
11
|
def initialize(attributes = {})
|
12
|
-
@attributes = attributes
|
12
|
+
@attributes = attributes && attributes.symbolize_keys
|
13
13
|
@errors = ActiveModel::Errors.new(self)
|
14
14
|
super
|
15
15
|
end
|
@@ -21,7 +21,7 @@ module ActiveModelSerializers
|
|
21
21
|
|
22
22
|
# Defaults to the downcased model name and updated_at
|
23
23
|
def cache_key
|
24
|
-
attributes.fetch(:cache_key) { "#{self.class.name.downcase}/#{id}-#{updated_at.strftime(
|
24
|
+
attributes.fetch(:cache_key) { "#{self.class.name.downcase}/#{id}-#{updated_at.strftime('%Y%m%d%H%M%S%9N')}" }
|
25
25
|
end
|
26
26
|
|
27
27
|
# Defaults to the time the serializer file was modified.
|
@@ -38,6 +38,7 @@ module ActiveModelSerializers
|
|
38
38
|
end
|
39
39
|
|
40
40
|
# The following methods are needed to be minimally implemented for ActiveModel::Errors
|
41
|
+
# :nocov:
|
41
42
|
def self.human_attribute_name(attr, _options = {})
|
42
43
|
attr
|
43
44
|
end
|
@@ -45,5 +46,6 @@ module ActiveModelSerializers
|
|
45
46
|
def self.lookup_ancestors
|
46
47
|
[self]
|
47
48
|
end
|
49
|
+
# :nocov:
|
48
50
|
end
|
49
51
|
end
|
@@ -23,7 +23,7 @@ module ActiveModelSerializers
|
|
23
23
|
# This hook is run after the action_controller railtie has set the configuration
|
24
24
|
# based on the *environment* configuration and before any config/initializers are run
|
25
25
|
# and also before eager_loading (if enabled).
|
26
|
-
initializer 'active_model_serializers.set_configs', :
|
26
|
+
initializer 'active_model_serializers.set_configs', after: 'action_controller.set_configs' do
|
27
27
|
ActiveModelSerializers.logger = Rails.configuration.action_controller.logger
|
28
28
|
ActiveModelSerializers.config.perform_caching = Rails.configuration.action_controller.perform_caching
|
29
29
|
# We want this hook to run after the config has been set, even if ActionController has already loaded.
|
@@ -32,11 +32,13 @@ module ActiveModelSerializers
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
# :nocov:
|
35
36
|
generators do |app|
|
36
37
|
Rails::Generators.configure!(app.config.generators)
|
37
38
|
Rails::Generators.hidden_namespaces.uniq!
|
38
39
|
require 'generators/rails/resource_override'
|
39
40
|
end
|
41
|
+
# :nocov:
|
40
42
|
|
41
43
|
if Rails.env.test?
|
42
44
|
ActionController::TestCase.send(:include, ActiveModelSerializers::Test::Schema)
|
@@ -22,44 +22,57 @@
|
|
22
22
|
# render jsonapi: model
|
23
23
|
#
|
24
24
|
# No wrapper format needed as it does not apply (i.e. no `wrap_parameters format: [jsonapi]`)
|
25
|
+
module ActiveModelSerializers
|
26
|
+
module Jsonapi
|
27
|
+
MEDIA_TYPE = 'application/vnd.api+json'.freeze
|
28
|
+
HEADERS = {
|
29
|
+
response: { 'CONTENT_TYPE'.freeze => MEDIA_TYPE },
|
30
|
+
request: { 'ACCEPT'.freeze => MEDIA_TYPE }
|
31
|
+
}.freeze
|
25
32
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
response: { 'CONTENT_TYPE'.freeze => MEDIA_TYPE },
|
30
|
-
request: { 'ACCEPT'.freeze => MEDIA_TYPE }
|
31
|
-
}.freeze
|
32
|
-
module ControllerSupport
|
33
|
-
def serialize_jsonapi(json, options)
|
34
|
-
options[:adapter] = :json_api
|
35
|
-
options.fetch(:serialization_context) { options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request) }
|
36
|
-
get_serializer(json, options)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
33
|
+
def self.install
|
34
|
+
# actionpack/lib/action_dispatch/http/mime_types.rb
|
35
|
+
Mime::Type.register MEDIA_TYPE, :jsonapi
|
40
36
|
|
41
|
-
|
42
|
-
|
37
|
+
if Rails::VERSION::MAJOR >= 5
|
38
|
+
ActionDispatch::Request.parameter_parsers[:jsonapi] = parser
|
39
|
+
else
|
40
|
+
ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime[:jsonapi]] = parser
|
41
|
+
end
|
43
42
|
|
44
|
-
|
45
|
-
|
43
|
+
# ref https://github.com/rails/rails/pull/21496
|
44
|
+
ActionController::Renderers.add :jsonapi do |json, options|
|
45
|
+
json = serialize_jsonapi(json, options).to_json(options) unless json.is_a?(String)
|
46
|
+
self.content_type ||= Mime[:jsonapi]
|
47
|
+
self.response_body = json
|
48
|
+
end
|
49
|
+
end
|
46
50
|
|
47
|
-
# Proposal: should actually deserialize the JSON API params
|
48
|
-
# to the hash format expected by `ActiveModel::Serializers::JSON`
|
49
|
-
# actionpack/lib/action_dispatch/http/parameters.rb
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
# Proposal: should actually deserialize the JSON API params
|
52
|
+
# to the hash format expected by `ActiveModel::Serializers::JSON`
|
53
|
+
# actionpack/lib/action_dispatch/http/parameters.rb
|
54
|
+
def self.parser
|
55
|
+
lambda do |body|
|
56
|
+
data = JSON.parse(body)
|
57
|
+
data = { _json: data } unless data.is_a?(Hash)
|
58
|
+
data.with_indifferent_access
|
59
|
+
end
|
60
|
+
end
|
55
61
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
62
|
+
module ControllerSupport
|
63
|
+
def serialize_jsonapi(json, options)
|
64
|
+
options[:adapter] = :json_api
|
65
|
+
options.fetch(:serialization_context) do
|
66
|
+
options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request)
|
67
|
+
end
|
68
|
+
get_serializer(json, options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
61
72
|
end
|
62
73
|
|
74
|
+
ActiveModelSerializers::Jsonapi.install
|
75
|
+
|
63
76
|
ActiveSupport.on_load(:action_controller) do
|
64
77
|
include ActiveModelSerializers::Jsonapi::ControllerSupport
|
65
78
|
end
|
@@ -38,9 +38,10 @@ module ActiveModelSerializers
|
|
38
38
|
|
39
39
|
def find_adapter
|
40
40
|
return resource unless serializer?
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
adapter = catch :no_serializer do
|
42
|
+
ActiveModelSerializers::Adapter.create(serializer_instance, adapter_opts)
|
43
|
+
end
|
44
|
+
adapter || resource
|
44
45
|
end
|
45
46
|
|
46
47
|
def serializer_instance
|
@@ -49,12 +50,12 @@ module ActiveModelSerializers
|
|
49
50
|
|
50
51
|
# Get serializer either explicitly :serializer or implicitly from resource
|
51
52
|
# Remove :serializer key from serializer_opts
|
52
|
-
#
|
53
|
+
# Remove :each_serializer if present and set as :serializer key
|
53
54
|
def serializer
|
54
55
|
@serializer ||=
|
55
56
|
begin
|
56
57
|
@serializer = serializer_opts.delete(:serializer)
|
57
|
-
@serializer ||= ActiveModel::Serializer.serializer_for(resource)
|
58
|
+
@serializer ||= ActiveModel::Serializer.serializer_for(resource, serializer_opts)
|
58
59
|
|
59
60
|
if serializer_opts.key?(:each_serializer)
|
60
61
|
serializer_opts[:serializer] = serializer_opts.delete(:each_serializer)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'active_support/core_ext/array/extract_options'
|
1
2
|
module ActiveModelSerializers
|
2
3
|
class SerializationContext
|
3
4
|
class << self
|
@@ -22,9 +23,15 @@ module ActiveModelSerializers
|
|
22
23
|
|
23
24
|
attr_reader :request_url, :query_parameters, :key_transform
|
24
25
|
|
25
|
-
def initialize(
|
26
|
-
|
27
|
-
|
26
|
+
def initialize(*args)
|
27
|
+
options = args.extract_options!
|
28
|
+
if args.size == 1
|
29
|
+
request = args.pop
|
30
|
+
options[:request_url] = request.original_url[/\A[^?]+/]
|
31
|
+
options[:query_parameters] = request.query_parameters
|
32
|
+
end
|
33
|
+
@request_url = options.delete(:request_url)
|
34
|
+
@query_parameters = options.delete(:query_parameters)
|
28
35
|
@url_helpers = options.delete(:url_helpers) || self.class.url_helpers
|
29
36
|
@default_url_options = options.delete(:default_url_options) || self.class.default_url_options
|
30
37
|
end
|
@@ -14,6 +14,7 @@ module ActiveModelSerializers
|
|
14
14
|
autoload :Adapter
|
15
15
|
autoload :JsonPointer
|
16
16
|
autoload :Deprecate
|
17
|
+
autoload :LookupChain
|
17
18
|
|
18
19
|
class << self; attr_accessor :logger; end
|
19
20
|
self.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
|
@@ -31,6 +32,12 @@ module ActiveModelSerializers
|
|
31
32
|
[file, lineno]
|
32
33
|
end
|
33
34
|
|
35
|
+
# Memoized default include directive
|
36
|
+
# @return [JSONAPI::IncludeDirective]
|
37
|
+
def self.default_include_directive
|
38
|
+
@default_include_directive ||= JSONAPI::IncludeDirective.new(config.default_includes, allow_wildcard: true)
|
39
|
+
end
|
40
|
+
|
34
41
|
require 'active_model/serializer/version'
|
35
42
|
require 'active_model/serializer'
|
36
43
|
require 'active_model/serializable_resource'
|
@@ -2,11 +2,11 @@ module Rails
|
|
2
2
|
module Generators
|
3
3
|
class SerializerGenerator < NamedBase
|
4
4
|
source_root File.expand_path('../templates', __FILE__)
|
5
|
-
check_class_collision :
|
5
|
+
check_class_collision suffix: 'Serializer'
|
6
6
|
|
7
|
-
argument :attributes, :
|
7
|
+
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
8
8
|
|
9
|
-
class_option :parent, :
|
9
|
+
class_option :parent, type: :string, desc: 'The parent class for the generated serializer'
|
10
10
|
|
11
11
|
def create_serializer_file
|
12
12
|
template 'serializer.rb.erb', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
|
@@ -25,7 +25,7 @@ module Rails
|
|
25
25
|
def parent_class_name
|
26
26
|
if options[:parent]
|
27
27
|
options[:parent]
|
28
|
-
elsif
|
28
|
+
elsif 'ApplicationSerializer'.safe_constantize
|
29
29
|
'ApplicationSerializer'
|
30
30
|
else
|
31
31
|
'ActiveModel::Serializer'
|
@@ -4,11 +4,13 @@ require 'active_model_serializers'
|
|
4
4
|
require 'grape/formatters/active_model_serializers'
|
5
5
|
require 'grape/helpers/active_model_serializers'
|
6
6
|
|
7
|
-
module Grape
|
8
|
-
|
7
|
+
module Grape
|
8
|
+
module ActiveModelSerializers
|
9
|
+
extend ActiveSupport::Concern
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
included do
|
12
|
+
formatter :json, Grape::Formatters::ActiveModelSerializers
|
13
|
+
helpers Grape::Helpers::ActiveModelSerializers
|
14
|
+
end
|
13
15
|
end
|
14
16
|
end
|
@@ -2,14 +2,31 @@
|
|
2
2
|
#
|
3
3
|
# Serializer options can be passed as a hash from your Grape endpoint using env[:active_model_serializer_options],
|
4
4
|
# or better yet user the render helper in Grape::Helpers::ActiveModelSerializers
|
5
|
+
|
6
|
+
require 'active_model_serializers/serialization_context'
|
7
|
+
|
5
8
|
module Grape
|
6
9
|
module Formatters
|
7
10
|
module ActiveModelSerializers
|
8
11
|
def self.call(resource, env)
|
9
|
-
serializer_options =
|
10
|
-
serializer_options.merge!(env[:active_model_serializer_options]) if env[:active_model_serializer_options]
|
12
|
+
serializer_options = build_serializer_options(env)
|
11
13
|
::ActiveModelSerializers::SerializableResource.new(resource, serializer_options).to_json
|
12
14
|
end
|
15
|
+
|
16
|
+
def self.build_serializer_options(env)
|
17
|
+
ams_options = env[:active_model_serializer_options] || {}
|
18
|
+
|
19
|
+
# Add serialization context
|
20
|
+
ams_options.fetch(:serialization_context) do
|
21
|
+
request = env['grape.request']
|
22
|
+
ams_options[:serialization_context] = ::ActiveModelSerializers::SerializationContext.new(
|
23
|
+
request_url: request.url[/\A[^?]+/],
|
24
|
+
query_parameters: request.params
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
ams_options
|
29
|
+
end
|
13
30
|
end
|
14
31
|
end
|
15
32
|
end
|
@@ -5,17 +5,17 @@ module ActionController
|
|
5
5
|
class AdapterSelectorTest < ActionController::TestCase
|
6
6
|
class AdapterSelectorTestController < ActionController::Base
|
7
7
|
def render_using_default_adapter
|
8
|
-
@profile = Profile.new(
|
8
|
+
@profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
|
9
9
|
render json: @profile
|
10
10
|
end
|
11
11
|
|
12
12
|
def render_using_adapter_override
|
13
|
-
@profile = Profile.new(
|
13
|
+
@profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
|
14
14
|
render json: @profile, adapter: :json_api
|
15
15
|
end
|
16
16
|
|
17
17
|
def render_skipping_adapter
|
18
|
-
@profile = Profile.new(
|
18
|
+
@profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
|
19
19
|
render json: @profile, adapter: false
|
20
20
|
end
|
21
21
|
end
|
@@ -32,7 +32,7 @@ module ActionController
|
|
32
32
|
|
33
33
|
expected = {
|
34
34
|
data: {
|
35
|
-
id:
|
35
|
+
id: @controller.instance_variable_get(:@profile).id.to_s,
|
36
36
|
type: 'profiles',
|
37
37
|
attributes: {
|
38
38
|
name: 'Name 1',
|
@@ -100,11 +100,12 @@ module ActionController
|
|
100
100
|
get :render_array_using_explicit_serializer_and_custom_serializers
|
101
101
|
|
102
102
|
expected = [
|
103
|
-
{
|
103
|
+
{
|
104
|
+
'title' => 'New Post',
|
104
105
|
'body' => 'Body',
|
105
|
-
'id' =>
|
106
|
+
'id' => @controller.instance_variable_get(:@post).id,
|
106
107
|
'comments' => [{ 'id' => 1 }, { 'id' => 2 }],
|
107
|
-
'author' => { 'id' =>
|
108
|
+
'author' => { 'id' => @controller.instance_variable_get(:@author).id }
|
108
109
|
}
|
109
110
|
]
|
110
111
|
|
@@ -122,7 +123,7 @@ module ActionController
|
|
122
123
|
id: 42,
|
123
124
|
lat: '-23.550520',
|
124
125
|
lng: '-46.633309',
|
125
|
-
|
126
|
+
address: 'Nowhere' # is a virtual attribute on LocationSerializer
|
126
127
|
}
|
127
128
|
]
|
128
129
|
}
|
@@ -4,6 +4,10 @@ module ActionController
|
|
4
4
|
module Serialization
|
5
5
|
class Json
|
6
6
|
class IncludeTest < ActionController::TestCase
|
7
|
+
INCLUDE_STRING = 'posts.comments'.freeze
|
8
|
+
INCLUDE_HASH = { posts: :comments }.freeze
|
9
|
+
DEEP_INCLUDE = 'posts.comments.author'.freeze
|
10
|
+
|
7
11
|
class IncludeTestController < ActionController::Base
|
8
12
|
def setup_data
|
9
13
|
ActionController::Base.cache_store.clear
|
@@ -38,17 +42,28 @@ module ActionController
|
|
38
42
|
|
39
43
|
def render_resource_with_include_hash
|
40
44
|
setup_data
|
41
|
-
render json: @author, include:
|
45
|
+
render json: @author, include: INCLUDE_HASH, adapter: :json
|
42
46
|
end
|
43
47
|
|
44
48
|
def render_resource_with_include_string
|
45
49
|
setup_data
|
46
|
-
render json: @author, include:
|
50
|
+
render json: @author, include: INCLUDE_STRING, adapter: :json
|
47
51
|
end
|
48
52
|
|
49
53
|
def render_resource_with_deep_include
|
50
54
|
setup_data
|
51
|
-
render json: @author, include:
|
55
|
+
render json: @author, include: DEEP_INCLUDE, adapter: :json
|
56
|
+
end
|
57
|
+
|
58
|
+
def render_without_recursive_relationships
|
59
|
+
# testing recursive includes ('**') can't have any cycles in the
|
60
|
+
# relationships, or we enter an infinite loop.
|
61
|
+
author = Author.new(id: 11, name: 'Jane Doe')
|
62
|
+
post = Post.new(id: 12, title: 'Hello World', body: 'My first post')
|
63
|
+
comment = Comment.new(id: 13, body: 'Commentary')
|
64
|
+
author.posts = [post]
|
65
|
+
post.comments = [comment]
|
66
|
+
render json: author
|
52
67
|
end
|
53
68
|
end
|
54
69
|
|
@@ -77,34 +92,90 @@ module ActionController
|
|
77
92
|
def test_render_resource_with_include_hash
|
78
93
|
get :render_resource_with_include_hash
|
79
94
|
response = JSON.parse(@response.body)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
95
|
+
|
96
|
+
assert_equal(expected_include_response, response)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_render_resource_with_include_string
|
100
|
+
get :render_resource_with_include_string
|
101
|
+
|
102
|
+
response = JSON.parse(@response.body)
|
103
|
+
|
104
|
+
assert_equal(expected_include_response, response)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_render_resource_with_deep_include
|
108
|
+
get :render_resource_with_deep_include
|
109
|
+
|
110
|
+
response = JSON.parse(@response.body)
|
111
|
+
|
112
|
+
assert_equal(expected_deep_include_response, response)
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_render_with_empty_default_includes
|
116
|
+
with_default_includes '' do
|
117
|
+
get :render_without_include
|
118
|
+
response = JSON.parse(@response.body)
|
119
|
+
expected = {
|
120
|
+
'author' => {
|
121
|
+
'id' => 1,
|
122
|
+
'name' => 'Steve K.'
|
123
|
+
}
|
124
|
+
}
|
125
|
+
assert_equal(expected, response)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_render_with_recursive_default_includes
|
130
|
+
with_default_includes '**' do
|
131
|
+
get :render_without_recursive_relationships
|
132
|
+
response = JSON.parse(@response.body)
|
133
|
+
|
134
|
+
expected = {
|
135
|
+
'id' => 11,
|
136
|
+
'name' => 'Jane Doe',
|
137
|
+
'roles' => nil,
|
138
|
+
'bio' => nil,
|
84
139
|
'posts' => [
|
85
140
|
{
|
86
|
-
'id' =>
|
141
|
+
'id' => 12,
|
142
|
+
'title' => 'Hello World',
|
143
|
+
'body' => 'My first post',
|
87
144
|
'comments' => [
|
88
145
|
{
|
89
|
-
'id' =>
|
90
|
-
|
91
|
-
|
92
|
-
'
|
146
|
+
'id' => 13,
|
147
|
+
'body' => 'Commentary',
|
148
|
+
'post' => nil, # not set to avoid infinite recursion
|
149
|
+
'author' => nil, # not set to avoid infinite recursion
|
93
150
|
}
|
94
|
-
]
|
151
|
+
],
|
152
|
+
'blog' => {
|
153
|
+
'id' => 999,
|
154
|
+
'name' => 'Custom blog',
|
155
|
+
'writer' => nil,
|
156
|
+
'articles' => nil
|
157
|
+
},
|
158
|
+
'author' => nil # not set to avoid infinite recursion
|
95
159
|
}
|
96
160
|
]
|
97
161
|
}
|
98
|
-
|
162
|
+
assert_equal(expected, response)
|
163
|
+
end
|
164
|
+
end
|
99
165
|
|
100
|
-
|
166
|
+
def test_render_with_includes_overrides_default_includes
|
167
|
+
with_default_includes '' do
|
168
|
+
get :render_resource_with_include_hash
|
169
|
+
response = JSON.parse(@response.body)
|
170
|
+
|
171
|
+
assert_equal(expected_include_response, response)
|
172
|
+
end
|
101
173
|
end
|
102
174
|
|
103
|
-
|
104
|
-
get :render_resource_with_include_string
|
175
|
+
private
|
105
176
|
|
106
|
-
|
107
|
-
|
177
|
+
def expected_include_response
|
178
|
+
{
|
108
179
|
'author' => {
|
109
180
|
'id' => 1,
|
110
181
|
'name' => 'Steve K.',
|
@@ -123,15 +194,10 @@ module ActionController
|
|
123
194
|
]
|
124
195
|
}
|
125
196
|
}
|
126
|
-
|
127
|
-
assert_equal(expected, response)
|
128
197
|
end
|
129
198
|
|
130
|
-
def
|
131
|
-
|
132
|
-
|
133
|
-
response = JSON.parse(@response.body)
|
134
|
-
expected = {
|
199
|
+
def expected_deep_include_response
|
200
|
+
{
|
135
201
|
'author' => {
|
136
202
|
'id' => 1,
|
137
203
|
'name' => 'Steve K.',
|
@@ -158,8 +224,21 @@ module ActionController
|
|
158
224
|
]
|
159
225
|
}
|
160
226
|
}
|
227
|
+
end
|
161
228
|
|
162
|
-
|
229
|
+
def with_default_includes(include_directive)
|
230
|
+
original = ActiveModelSerializers.config.default_includes
|
231
|
+
ActiveModelSerializers.config.default_includes = include_directive
|
232
|
+
clear_include_directive_cache
|
233
|
+
yield
|
234
|
+
ensure
|
235
|
+
ActiveModelSerializers.config.default_includes = original
|
236
|
+
clear_include_directive_cache
|
237
|
+
end
|
238
|
+
|
239
|
+
def clear_include_directive_cache
|
240
|
+
ActiveModelSerializers
|
241
|
+
.instance_variable_set(:@default_include_directive, nil)
|
163
242
|
end
|
164
243
|
end
|
165
244
|
end
|
@@ -7,13 +7,12 @@ module ActionController
|
|
7
7
|
def test_active_model_with_multiple_errors
|
8
8
|
get :render_resource_with_errors
|
9
9
|
|
10
|
-
expected_errors_object =
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
]
|
10
|
+
expected_errors_object = {
|
11
|
+
errors: [
|
12
|
+
{ source: { pointer: '/data/attributes/name' }, detail: 'cannot be nil' },
|
13
|
+
{ source: { pointer: '/data/attributes/name' }, detail: 'must be longer' },
|
14
|
+
{ source: { pointer: '/data/attributes/id' }, detail: 'must be a uuid' }
|
15
|
+
]
|
17
16
|
}.to_json
|
18
17
|
assert_equal json_reponse_body.to_json, expected_errors_object
|
19
18
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
module Serialization
|
5
|
+
class JsonApi
|
6
|
+
class FieldsTest < ActionController::TestCase
|
7
|
+
class FieldsTestController < ActionController::Base
|
8
|
+
class PostSerializer < ActiveModel::Serializer
|
9
|
+
type 'posts'
|
10
|
+
attributes :title, :body, :publish_at
|
11
|
+
belongs_to :author
|
12
|
+
has_many :comments
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup_post
|
16
|
+
ActionController::Base.cache_store.clear
|
17
|
+
@author = Author.new(id: 1, first_name: 'Bob', last_name: 'Jones')
|
18
|
+
@comment1 = Comment.new(id: 7, body: 'cool', author: @author)
|
19
|
+
@comment2 = Comment.new(id: 12, body: 'awesome', author: @author)
|
20
|
+
@post = Post.new(id: 1337, title: 'Title 1', body: 'Body 1',
|
21
|
+
author: @author, comments: [@comment1, @comment2],
|
22
|
+
publish_at: '2020-03-16T03:55:25.291Z')
|
23
|
+
@comment1.post = @post
|
24
|
+
@comment2.post = @post
|
25
|
+
end
|
26
|
+
|
27
|
+
def render_fields_works_on_relationships
|
28
|
+
setup_post
|
29
|
+
render json: @post, serializer: PostSerializer, adapter: :json_api, fields: { posts: [:author] }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
tests FieldsTestController
|
34
|
+
|
35
|
+
test 'fields works on relationships' do
|
36
|
+
get :render_fields_works_on_relationships
|
37
|
+
response = JSON.parse(@response.body)
|
38
|
+
expected = {
|
39
|
+
'data' => {
|
40
|
+
'id' => '1337',
|
41
|
+
'type' => 'posts',
|
42
|
+
'relationships' => {
|
43
|
+
'author' => {
|
44
|
+
'data' => {
|
45
|
+
'id' => '1',
|
46
|
+
'type' => 'authors'
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
assert_equal expected, response
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|