active_model_serializers 0.8.3 → 0.10.0
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/.github/ISSUE_TEMPLATE.md +29 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +104 -0
- data/.rubocop_todo.yml +167 -0
- data/.simplecov +110 -0
- data/.travis.yml +39 -24
- data/CHANGELOG.md +465 -6
- data/CONTRIBUTING.md +105 -0
- data/Gemfile +50 -1
- data/{MIT-LICENSE.txt → MIT-LICENSE} +3 -2
- data/README.md +102 -590
- data/Rakefile +93 -8
- data/active_model_serializers.gemspec +65 -23
- data/appveyor.yml +24 -0
- data/bin/bench +171 -0
- data/bin/bench_regression +316 -0
- data/bin/serve_benchmark +39 -0
- data/docs/ARCHITECTURE.md +126 -0
- data/docs/README.md +40 -0
- data/docs/STYLE.md +58 -0
- data/docs/general/adapters.md +245 -0
- data/docs/general/caching.md +52 -0
- data/docs/general/configuration_options.md +100 -0
- data/docs/general/deserialization.md +100 -0
- data/docs/general/getting_started.md +133 -0
- data/docs/general/instrumentation.md +40 -0
- data/docs/general/key_transforms.md +40 -0
- data/docs/general/logging.md +14 -0
- data/docs/general/rendering.md +255 -0
- data/docs/general/serializers.md +372 -0
- data/docs/how-open-source-maintained.jpg +0 -0
- data/docs/howto/add_pagination_links.md +139 -0
- data/docs/howto/add_root_key.md +51 -0
- data/docs/howto/outside_controller_use.md +58 -0
- data/docs/howto/passing_arbitrary_options.md +27 -0
- data/docs/howto/serialize_poro.md +32 -0
- data/docs/howto/test.md +152 -0
- data/docs/integrations/ember-and-json-api.md +112 -0
- data/docs/integrations/grape.md +19 -0
- data/docs/jsonapi/errors.md +56 -0
- data/docs/jsonapi/schema/schema.json +366 -0
- data/docs/jsonapi/schema.md +151 -0
- data/docs/rfcs/0000-namespace.md +106 -0
- data/docs/rfcs/template.md +15 -0
- data/lib/action_controller/serialization.rb +31 -36
- data/lib/active_model/serializable_resource.rb +11 -0
- data/lib/active_model/serializer/adapter/attributes.rb +15 -0
- data/lib/active_model/serializer/adapter/base.rb +16 -0
- data/lib/active_model/serializer/adapter/json.rb +15 -0
- data/lib/active_model/serializer/adapter/json_api.rb +15 -0
- data/lib/active_model/serializer/adapter/null.rb +15 -0
- data/lib/active_model/serializer/adapter.rb +24 -0
- data/lib/active_model/serializer/array_serializer.rb +9 -0
- data/lib/active_model/serializer/association.rb +19 -0
- data/lib/active_model/serializer/associations.rb +87 -220
- data/lib/active_model/serializer/attribute.rb +25 -0
- data/lib/active_model/serializer/attributes.rb +82 -0
- data/lib/active_model/serializer/belongs_to_reflection.rb +10 -0
- data/lib/active_model/serializer/caching.rb +333 -0
- data/lib/active_model/serializer/collection_reflection.rb +7 -0
- data/lib/active_model/serializer/collection_serializer.rb +64 -0
- data/lib/active_model/serializer/configuration.rb +35 -0
- data/lib/active_model/serializer/error_serializer.rb +10 -0
- data/lib/active_model/serializer/errors_serializer.rb +27 -0
- data/lib/active_model/serializer/field.rb +90 -0
- data/lib/active_model/serializer/fieldset.rb +31 -0
- data/lib/active_model/serializer/has_many_reflection.rb +10 -0
- data/lib/active_model/serializer/has_one_reflection.rb +10 -0
- data/lib/active_model/serializer/include_tree.rb +111 -0
- data/lib/active_model/serializer/links.rb +35 -0
- data/lib/active_model/serializer/lint.rb +146 -0
- data/lib/active_model/serializer/meta.rb +29 -0
- data/lib/active_model/serializer/null.rb +17 -0
- data/lib/active_model/serializer/reflection.rb +147 -0
- data/lib/active_model/serializer/singular_reflection.rb +7 -0
- data/lib/active_model/serializer/type.rb +25 -0
- data/lib/active_model/{serializers → serializer}/version.rb +1 -1
- data/lib/active_model/serializer.rb +158 -481
- data/lib/active_model_serializers/adapter/attributes.rb +76 -0
- data/lib/active_model_serializers/adapter/base.rb +83 -0
- data/lib/active_model_serializers/adapter/json.rb +21 -0
- data/lib/active_model_serializers/adapter/json_api/deserialization.rb +213 -0
- data/lib/active_model_serializers/adapter/json_api/error.rb +96 -0
- data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +49 -0
- data/lib/active_model_serializers/adapter/json_api/link.rb +83 -0
- data/lib/active_model_serializers/adapter/json_api/meta.rb +37 -0
- data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +62 -0
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +52 -0
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +37 -0
- data/lib/active_model_serializers/adapter/json_api.rb +516 -0
- data/lib/active_model_serializers/adapter/null.rb +9 -0
- data/lib/active_model_serializers/adapter.rb +92 -0
- data/lib/active_model_serializers/callbacks.rb +55 -0
- data/lib/active_model_serializers/deprecate.rb +55 -0
- data/lib/active_model_serializers/deserialization.rb +13 -0
- data/lib/active_model_serializers/json_pointer.rb +14 -0
- data/lib/active_model_serializers/key_transform.rb +70 -0
- data/lib/active_model_serializers/logging.rb +122 -0
- data/lib/active_model_serializers/model.rb +49 -0
- data/lib/active_model_serializers/railtie.rb +46 -0
- data/lib/active_model_serializers/register_jsonapi_renderer.rb +65 -0
- data/lib/active_model_serializers/serializable_resource.rb +81 -0
- data/lib/active_model_serializers/serialization_context.rb +32 -0
- data/lib/active_model_serializers/test/schema.rb +138 -0
- data/lib/active_model_serializers/test/serializer.rb +125 -0
- data/lib/active_model_serializers/test.rb +7 -0
- data/lib/active_model_serializers.rb +32 -89
- data/lib/generators/rails/USAGE +6 -0
- data/lib/generators/rails/resource_override.rb +10 -0
- data/lib/generators/rails/serializer_generator.rb +36 -0
- data/lib/generators/rails/templates/serializer.rb.erb +8 -0
- data/lib/grape/active_model_serializers.rb +14 -0
- data/lib/grape/formatters/active_model_serializers.rb +15 -0
- data/lib/grape/helpers/active_model_serializers.rb +16 -0
- data/test/action_controller/adapter_selector_test.rb +53 -0
- data/test/action_controller/explicit_serializer_test.rb +134 -0
- data/test/action_controller/json/include_test.rb +167 -0
- data/test/action_controller/json_api/deserialization_test.rb +112 -0
- data/test/action_controller/json_api/errors_test.rb +41 -0
- data/test/action_controller/json_api/linked_test.rb +197 -0
- data/test/action_controller/json_api/pagination_test.rb +116 -0
- data/test/action_controller/json_api/transform_test.rb +181 -0
- data/test/action_controller/serialization_scope_name_test.rb +229 -0
- data/test/action_controller/serialization_test.rb +469 -0
- data/test/active_model_serializers/adapter_for_test.rb +208 -0
- data/test/active_model_serializers/json_pointer_test.rb +20 -0
- data/test/active_model_serializers/key_transform_test.rb +263 -0
- data/test/active_model_serializers/logging_test.rb +77 -0
- data/test/active_model_serializers/model_test.rb +9 -0
- data/test/active_model_serializers/railtie_test_isolated.rb +63 -0
- data/test/active_model_serializers/serialization_context_test_isolated.rb +58 -0
- data/test/active_model_serializers/test/schema_test.rb +130 -0
- data/test/active_model_serializers/test/serializer_test.rb +62 -0
- data/test/active_record_test.rb +9 -0
- data/test/adapter/deprecation_test.rb +100 -0
- data/test/adapter/json/belongs_to_test.rb +45 -0
- data/test/adapter/json/collection_test.rb +90 -0
- data/test/adapter/json/has_many_test.rb +45 -0
- data/test/adapter/json/transform_test.rb +93 -0
- data/test/adapter/json_api/belongs_to_test.rb +155 -0
- data/test/adapter/json_api/collection_test.rb +95 -0
- data/test/adapter/json_api/errors_test.rb +78 -0
- data/test/adapter/json_api/fields_test.rb +87 -0
- data/test/adapter/json_api/has_many_embed_ids_test.rb +43 -0
- data/test/adapter/json_api/has_many_explicit_serializer_test.rb +96 -0
- data/test/adapter/json_api/has_many_test.rb +144 -0
- data/test/adapter/json_api/has_one_test.rb +80 -0
- data/test/adapter/json_api/json_api_test.rb +35 -0
- data/test/adapter/json_api/linked_test.rb +392 -0
- data/test/adapter/json_api/links_test.rb +93 -0
- data/test/adapter/json_api/pagination_links_test.rb +166 -0
- data/test/adapter/json_api/parse_test.rb +137 -0
- data/test/adapter/json_api/relationship_test.rb +161 -0
- data/test/adapter/json_api/relationships_test.rb +199 -0
- data/test/adapter/json_api/resource_identifier_test.rb +85 -0
- data/test/adapter/json_api/resource_meta_test.rb +100 -0
- data/test/adapter/json_api/toplevel_jsonapi_test.rb +82 -0
- data/test/adapter/json_api/transform_test.rb +502 -0
- data/test/adapter/json_api/type_test.rb +61 -0
- data/test/adapter/json_test.rb +45 -0
- data/test/adapter/null_test.rb +23 -0
- data/test/adapter/polymorphic_test.rb +171 -0
- data/test/adapter_test.rb +67 -0
- data/test/array_serializer_test.rb +20 -73
- data/test/benchmark/app.rb +65 -0
- data/test/benchmark/benchmarking_support.rb +67 -0
- data/test/benchmark/bm_caching.rb +119 -0
- data/test/benchmark/bm_transform.rb +34 -0
- data/test/benchmark/config.ru +3 -0
- data/test/benchmark/controllers.rb +84 -0
- data/test/benchmark/fixtures.rb +219 -0
- data/test/cache_test.rb +485 -0
- data/test/collection_serializer_test.rb +110 -0
- data/test/fixtures/active_record.rb +78 -0
- data/test/fixtures/poro.rb +282 -0
- data/test/generators/scaffold_controller_generator_test.rb +24 -0
- data/test/generators/serializer_generator_test.rb +57 -0
- data/test/grape_test.rb +82 -0
- data/test/include_tree/from_include_args_test.rb +26 -0
- data/test/include_tree/from_string_test.rb +94 -0
- data/test/include_tree/include_args_to_hash_test.rb +64 -0
- data/test/lint_test.rb +49 -0
- data/test/logger_test.rb +18 -0
- data/test/poro_test.rb +9 -0
- data/test/serializable_resource_test.rb +83 -0
- data/test/serializers/association_macros_test.rb +36 -0
- data/test/serializers/associations_test.rb +295 -0
- data/test/serializers/attribute_test.rb +151 -0
- data/test/serializers/attributes_test.rb +52 -0
- data/test/serializers/caching_configuration_test_isolated.rb +170 -0
- data/test/serializers/configuration_test.rb +32 -0
- data/test/serializers/fieldset_test.rb +14 -0
- data/test/serializers/meta_test.rb +196 -0
- data/test/serializers/options_test.rb +21 -0
- data/test/serializers/read_attribute_for_serialization_test.rb +79 -0
- data/test/serializers/root_test.rb +21 -0
- data/test/serializers/serialization_test.rb +55 -0
- data/test/serializers/serializer_for_test.rb +134 -0
- data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
- data/test/support/isolated_unit.rb +79 -0
- data/test/support/rails5_shims.rb +47 -0
- data/test/support/rails_app.rb +45 -0
- data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
- data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +6 -0
- data/test/support/schemas/custom/show.json +7 -0
- data/test/support/schemas/hyper_schema.json +93 -0
- data/test/support/schemas/render_using_json_api.json +43 -0
- data/test/support/schemas/simple_json_pointers.json +10 -0
- data/test/support/serialization_testing.rb +53 -0
- data/test/test_helper.rb +48 -23
- metadata +449 -43
- data/DESIGN.textile +0 -586
- data/Gemfile.edge +0 -9
- data/bench/perf.rb +0 -43
- data/cruft.md +0 -19
- data/lib/active_model/array_serializer.rb +0 -104
- data/lib/active_record/serializer_override.rb +0 -16
- data/lib/generators/resource_override.rb +0 -13
- data/lib/generators/serializer/USAGE +0 -9
- data/lib/generators/serializer/serializer_generator.rb +0 -42
- data/lib/generators/serializer/templates/serializer.rb +0 -19
- data/test/association_test.rb +0 -592
- data/test/caching_test.rb +0 -96
- data/test/generators_test.rb +0 -85
- data/test/no_serialization_scope_test.rb +0 -34
- data/test/serialization_scope_name_test.rb +0 -67
- data/test/serialization_test.rb +0 -392
- data/test/serializer_support_test.rb +0 -51
- data/test/serializer_test.rb +0 -1465
- data/test/test_fakes.rb +0 -217
|
@@ -1,32 +1,18 @@
|
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
|
2
|
+
require 'active_model_serializers/serialization_context'
|
|
3
|
+
|
|
1
4
|
module ActionController
|
|
2
|
-
# Action Controller Serialization
|
|
3
|
-
#
|
|
4
|
-
# Overrides render :json to check if the given object implements +active_model_serializer+
|
|
5
|
-
# as a method. If so, use the returned serializer instead of calling +to_json+ on the object.
|
|
6
|
-
#
|
|
7
|
-
# This module also provides a serialization_scope method that allows you to configure the
|
|
8
|
-
# +serialization_scope+ of the serializer. Most apps will likely set the +serialization_scope+
|
|
9
|
-
# to the current user:
|
|
10
|
-
#
|
|
11
|
-
# class ApplicationController < ActionController::Base
|
|
12
|
-
# serialization_scope :current_user
|
|
13
|
-
# end
|
|
14
|
-
#
|
|
15
|
-
# If you need more complex scope rules, you can simply override the serialization_scope:
|
|
16
|
-
#
|
|
17
|
-
# class ApplicationController < ActionController::Base
|
|
18
|
-
# private
|
|
19
|
-
#
|
|
20
|
-
# def serialization_scope
|
|
21
|
-
# current_user
|
|
22
|
-
# end
|
|
23
|
-
# end
|
|
24
|
-
#
|
|
25
5
|
module Serialization
|
|
26
6
|
extend ActiveSupport::Concern
|
|
27
7
|
|
|
28
8
|
include ActionController::Renderers
|
|
29
9
|
|
|
10
|
+
module ClassMethods
|
|
11
|
+
def serialization_scope(scope)
|
|
12
|
+
self._serialization_scope = scope
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
30
16
|
included do
|
|
31
17
|
class_attribute :_serialization_scope
|
|
32
18
|
self._serialization_scope = :current_user
|
|
@@ -37,24 +23,33 @@ module ActionController
|
|
|
37
23
|
respond_to?(_serialization_scope, true)
|
|
38
24
|
end
|
|
39
25
|
|
|
40
|
-
def
|
|
26
|
+
def get_serializer(resource, options = {})
|
|
27
|
+
if !use_adapter?
|
|
28
|
+
warn 'ActionController::Serialization#use_adapter? has been removed. '\
|
|
29
|
+
"Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
|
|
30
|
+
options[:adapter] = false
|
|
31
|
+
end
|
|
32
|
+
serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)
|
|
33
|
+
serializable_resource.serialization_scope ||= options.fetch(:scope) { serialization_scope }
|
|
34
|
+
serializable_resource.serialization_scope_name = options.fetch(:scope_name) { _serialization_scope }
|
|
35
|
+
# For compatibility with the JSON renderer: `json.to_json(options) if json.is_a?(String)`.
|
|
36
|
+
# Otherwise, since `serializable_resource` is not a string, the renderer would call
|
|
37
|
+
# `to_json` on a String and given odd results, such as `"".to_json #=> '""'`
|
|
38
|
+
serializable_resource.adapter.is_a?(String) ? serializable_resource.adapter : serializable_resource
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Deprecated
|
|
42
|
+
def use_adapter?
|
|
43
|
+
true
|
|
41
44
|
end
|
|
42
45
|
|
|
43
46
|
[:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
|
|
44
47
|
define_method renderer_method do |resource, options|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if json
|
|
48
|
-
super(json, options)
|
|
49
|
-
else
|
|
50
|
-
super(resource, options)
|
|
48
|
+
options.fetch(:serialization_context) do
|
|
49
|
+
options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, options)
|
|
51
50
|
end
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
module ClassMethods
|
|
56
|
-
def serialization_scope(scope)
|
|
57
|
-
self._serialization_scope = scope
|
|
51
|
+
serializable_resource = get_serializer(resource, options)
|
|
52
|
+
super(serializable_resource, options)
|
|
58
53
|
end
|
|
59
54
|
end
|
|
60
55
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
class Serializer
|
|
3
|
+
module Adapter
|
|
4
|
+
class Attributes < DelegateClass(ActiveModelSerializers::Adapter::Attributes)
|
|
5
|
+
def initialize(serializer, options = {})
|
|
6
|
+
super(ActiveModelSerializers::Adapter::Attributes.new(serializer, options))
|
|
7
|
+
end
|
|
8
|
+
class << self
|
|
9
|
+
extend ActiveModelSerializers::Deprecate
|
|
10
|
+
deprecate :new, 'ActiveModelSerializers::Adapter::Json.'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
class Serializer
|
|
3
|
+
module Adapter
|
|
4
|
+
class Base < DelegateClass(ActiveModelSerializers::Adapter::Base)
|
|
5
|
+
class << self
|
|
6
|
+
extend ActiveModelSerializers::Deprecate
|
|
7
|
+
deprecate :inherited, 'ActiveModelSerializers::Adapter::Base.'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(serializer, options = {})
|
|
11
|
+
super(ActiveModelSerializers::Adapter::Base.new(serializer, options))
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
class Serializer
|
|
3
|
+
module Adapter
|
|
4
|
+
class Json < DelegateClass(ActiveModelSerializers::Adapter::Json)
|
|
5
|
+
def initialize(serializer, options = {})
|
|
6
|
+
super(ActiveModelSerializers::Adapter::Json.new(serializer, options))
|
|
7
|
+
end
|
|
8
|
+
class << self
|
|
9
|
+
extend ActiveModelSerializers::Deprecate
|
|
10
|
+
deprecate :new, 'ActiveModelSerializers::Adapter::Json.new'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
class Serializer
|
|
3
|
+
module Adapter
|
|
4
|
+
class JsonApi < DelegateClass(ActiveModelSerializers::Adapter::JsonApi)
|
|
5
|
+
def initialize(serializer, options = {})
|
|
6
|
+
super(ActiveModelSerializers::Adapter::JsonApi.new(serializer, options))
|
|
7
|
+
end
|
|
8
|
+
class << self
|
|
9
|
+
extend ActiveModelSerializers::Deprecate
|
|
10
|
+
deprecate :new, 'ActiveModelSerializers::Adapter::JsonApi.new'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
class Serializer
|
|
3
|
+
module Adapter
|
|
4
|
+
class Null < DelegateClass(ActiveModelSerializers::Adapter::Null)
|
|
5
|
+
def initialize(serializer, options = {})
|
|
6
|
+
super(ActiveModelSerializers::Adapter::Null.new(serializer, options))
|
|
7
|
+
end
|
|
8
|
+
class << self
|
|
9
|
+
extend ActiveModelSerializers::Deprecate
|
|
10
|
+
deprecate :new, 'ActiveModelSerializers::Adapter::Null.new'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'active_model_serializers/adapter'
|
|
2
|
+
require 'active_model_serializers/deprecate'
|
|
3
|
+
|
|
4
|
+
module ActiveModel
|
|
5
|
+
class Serializer
|
|
6
|
+
# @deprecated Use ActiveModelSerializers::Adapter instead
|
|
7
|
+
module Adapter
|
|
8
|
+
class << self
|
|
9
|
+
extend ActiveModelSerializers::Deprecate
|
|
10
|
+
|
|
11
|
+
DEPRECATED_METHODS = [:create, :adapter_class, :adapter_map, :adapters, :register, :lookup].freeze
|
|
12
|
+
DEPRECATED_METHODS.each do |method|
|
|
13
|
+
delegate_and_deprecate method, ActiveModelSerializers::Adapter
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
require 'active_model/serializer/adapter/base'
|
|
21
|
+
require 'active_model/serializer/adapter/null'
|
|
22
|
+
require 'active_model/serializer/adapter/attributes'
|
|
23
|
+
require 'active_model/serializer/adapter/json'
|
|
24
|
+
require 'active_model/serializer/adapter/json_api'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
require 'active_model/serializer/collection_serializer'
|
|
2
|
+
class ActiveModel::Serializer
|
|
3
|
+
class ArraySerializer < CollectionSerializer
|
|
4
|
+
class << self
|
|
5
|
+
extend ActiveModelSerializers::Deprecate
|
|
6
|
+
deprecate :new, 'ActiveModel::Serializer::CollectionSerializer.'
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
class Serializer
|
|
3
|
+
# This class hold all information about serializer's association.
|
|
4
|
+
#
|
|
5
|
+
# @attr [Symbol] name
|
|
6
|
+
# @attr [ActiveModel::Serializer] serializer
|
|
7
|
+
# @attr [Hash{Symbol => Object}] options
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# Association.new(:comments, CommentSummarySerializer)
|
|
11
|
+
#
|
|
12
|
+
Association = Struct.new(:name, :serializer, :options, :links, :meta) do
|
|
13
|
+
# @return [Symbol]
|
|
14
|
+
def key
|
|
15
|
+
options.fetch(:key, name)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,230 +1,97 @@
|
|
|
1
1
|
module ActiveModel
|
|
2
2
|
class Serializer
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
self.options = {}
|
|
32
|
-
|
|
33
|
-
def initialize(name, source, options={})
|
|
34
|
-
@name = name
|
|
35
|
-
@source = source
|
|
36
|
-
@options = options
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def option(key, default=nil)
|
|
40
|
-
if @options.key?(key)
|
|
41
|
-
@options[key]
|
|
42
|
-
elsif self.class.options.key?(key)
|
|
43
|
-
self.class.options[key]
|
|
44
|
-
else
|
|
45
|
-
default
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def target_serializer
|
|
50
|
-
serializer = option(:serializer)
|
|
51
|
-
serializer.is_a?(String) ? serializer.constantize : serializer
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def source_serializer
|
|
55
|
-
@source
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def key
|
|
59
|
-
option(:key) || @name
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def root
|
|
63
|
-
option(:root) || @name
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def name
|
|
67
|
-
option(:name) || @name
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def associated_object
|
|
71
|
-
option(:value) || source_serializer.send(name)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def embed_ids?
|
|
75
|
-
[:id, :ids].include? option(:embed, source_serializer._embed)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def embed_objects?
|
|
79
|
-
[:object, :objects].include? option(:embed, source_serializer._embed)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def embed_in_root?
|
|
83
|
-
option(:include, source_serializer._root_embed)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def embeddable?
|
|
87
|
-
!associated_object.nil?
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
protected
|
|
91
|
-
|
|
92
|
-
def find_serializable(object)
|
|
93
|
-
if target_serializer
|
|
94
|
-
target_serializer.new(object, source_serializer.options)
|
|
95
|
-
elsif object.respond_to?(:active_model_serializer) && (ams = object.active_model_serializer)
|
|
96
|
-
ams.new(object, source_serializer.options)
|
|
97
|
-
else
|
|
98
|
-
object
|
|
99
|
-
end
|
|
100
|
-
end
|
|
3
|
+
# Defines an association in the object should be rendered.
|
|
4
|
+
#
|
|
5
|
+
# The serializer object should implement the association name
|
|
6
|
+
# as a method which should return an array when invoked. If a method
|
|
7
|
+
# with the association name does not exist, the association name is
|
|
8
|
+
# dispatched to the serialized object.
|
|
9
|
+
#
|
|
10
|
+
module Associations
|
|
11
|
+
extend ActiveSupport::Concern
|
|
12
|
+
|
|
13
|
+
DEFAULT_INCLUDE_TREE = ActiveModel::Serializer::IncludeTree.from_string('*')
|
|
14
|
+
|
|
15
|
+
included do
|
|
16
|
+
with_options instance_writer: false, instance_reader: true do |serializer|
|
|
17
|
+
serializer.class_attribute :_reflections
|
|
18
|
+
self._reflections ||= []
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
extend ActiveSupport::Autoload
|
|
22
|
+
autoload :Association
|
|
23
|
+
autoload :Reflection
|
|
24
|
+
autoload :SingularReflection
|
|
25
|
+
autoload :CollectionReflection
|
|
26
|
+
autoload :BelongsToReflection
|
|
27
|
+
autoload :HasOneReflection
|
|
28
|
+
autoload :HasManyReflection
|
|
101
29
|
end
|
|
102
30
|
|
|
103
|
-
|
|
104
|
-
def
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
31
|
+
module ClassMethods
|
|
32
|
+
def inherited(base)
|
|
33
|
+
super
|
|
34
|
+
base._reflections = _reflections.dup
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @param [Symbol] name of the association
|
|
38
|
+
# @param [Hash<Symbol => any>] options for the reflection
|
|
39
|
+
# @return [void]
|
|
40
|
+
#
|
|
41
|
+
# @example
|
|
42
|
+
# has_many :comments, serializer: CommentSummarySerializer
|
|
43
|
+
#
|
|
44
|
+
def has_many(name, options = {}, &block)
|
|
45
|
+
associate(HasManyReflection.new(name, options, block))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# @param [Symbol] name of the association
|
|
49
|
+
# @param [Hash<Symbol => any>] options for the reflection
|
|
50
|
+
# @return [void]
|
|
51
|
+
#
|
|
52
|
+
# @example
|
|
53
|
+
# belongs_to :author, serializer: AuthorSerializer
|
|
54
|
+
#
|
|
55
|
+
def belongs_to(name, options = {}, &block)
|
|
56
|
+
associate(BelongsToReflection.new(name, options, block))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @param [Symbol] name of the association
|
|
60
|
+
# @param [Hash<Symbol => any>] options for the reflection
|
|
61
|
+
# @return [void]
|
|
62
|
+
#
|
|
63
|
+
# @example
|
|
64
|
+
# has_one :author, serializer: AuthorSerializer
|
|
65
|
+
#
|
|
66
|
+
def has_one(name, options = {}, &block)
|
|
67
|
+
associate(HasOneReflection.new(name, options, block))
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# Add reflection and define {name} accessor.
|
|
73
|
+
# @param [ActiveModel::Serializer::Reflection] reflection
|
|
74
|
+
# @return [void]
|
|
75
|
+
#
|
|
76
|
+
# @api private
|
|
77
|
+
#
|
|
78
|
+
def associate(reflection)
|
|
79
|
+
self._reflections << reflection
|
|
143
80
|
end
|
|
144
81
|
end
|
|
145
82
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def root
|
|
160
|
-
if root = option(:root)
|
|
161
|
-
root
|
|
162
|
-
elsif polymorphic?
|
|
163
|
-
associated_object.class.to_s.pluralize.demodulize.underscore.to_sym
|
|
164
|
-
else
|
|
165
|
-
@name.to_s.pluralize.to_sym
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def key
|
|
170
|
-
if key = option(:key)
|
|
171
|
-
key
|
|
172
|
-
elsif embed_ids? && !polymorphic?
|
|
173
|
-
"#{@name}_id".to_sym
|
|
174
|
-
else
|
|
175
|
-
@name
|
|
176
|
-
end
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def embed_key
|
|
180
|
-
if key = option(:embed_key)
|
|
181
|
-
key
|
|
182
|
-
else
|
|
183
|
-
:id
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def polymorphic_key
|
|
188
|
-
associated_object.class.to_s.demodulize.underscore.to_sym
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def serialize
|
|
192
|
-
object = associated_object
|
|
193
|
-
|
|
194
|
-
if object && polymorphic?
|
|
195
|
-
{
|
|
196
|
-
:type => polymorphic_key,
|
|
197
|
-
polymorphic_key => find_serializable(object).serializable_hash
|
|
198
|
-
}
|
|
199
|
-
elsif object
|
|
200
|
-
find_serializable(object).serializable_hash
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def serializables
|
|
205
|
-
object = associated_object
|
|
206
|
-
value = object && find_serializable(object)
|
|
207
|
-
value ? [value] : []
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def serialize_ids
|
|
211
|
-
id_key = "#{@name}_id".to_sym
|
|
212
|
-
|
|
213
|
-
if polymorphic?
|
|
214
|
-
if associated_object
|
|
215
|
-
{
|
|
216
|
-
:type => polymorphic_key,
|
|
217
|
-
:id => associated_object.read_attribute_for_serialization(embed_key)
|
|
218
|
-
}
|
|
219
|
-
else
|
|
220
|
-
nil
|
|
221
|
-
end
|
|
222
|
-
elsif !option(:embed_key) && !source_serializer.respond_to?(@name.to_s) && source_serializer.object.respond_to?(id_key)
|
|
223
|
-
source_serializer.object.read_attribute_for_serialization(id_key)
|
|
224
|
-
elsif associated_object
|
|
225
|
-
associated_object.read_attribute_for_serialization(embed_key)
|
|
226
|
-
else
|
|
227
|
-
nil
|
|
83
|
+
# @param [IncludeTree] include_tree (defaults to all associations when not provided)
|
|
84
|
+
# @return [Enumerator<Association>]
|
|
85
|
+
#
|
|
86
|
+
def associations(include_tree = DEFAULT_INCLUDE_TREE)
|
|
87
|
+
return unless object
|
|
88
|
+
|
|
89
|
+
Enumerator.new do |y|
|
|
90
|
+
self.class._reflections.each do |reflection|
|
|
91
|
+
next if reflection.excluded?(self)
|
|
92
|
+
key = reflection.options.fetch(:key, reflection.name)
|
|
93
|
+
next unless include_tree.key?(key)
|
|
94
|
+
y.yield reflection.build_association(self, instance_options)
|
|
228
95
|
end
|
|
229
96
|
end
|
|
230
97
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'active_model/serializer/field'
|
|
2
|
+
|
|
3
|
+
module ActiveModel
|
|
4
|
+
class Serializer
|
|
5
|
+
# Holds all the meta-data about an attribute as it was specified in the
|
|
6
|
+
# ActiveModel::Serializer class.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# class PostSerializer < ActiveModel::Serializer
|
|
10
|
+
# attribute :content
|
|
11
|
+
# attribute :name, key: :title
|
|
12
|
+
# attribute :email, key: :author_email, if: :user_logged_in?
|
|
13
|
+
# attribute :preview do
|
|
14
|
+
# truncate(object.content)
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# def user_logged_in?
|
|
18
|
+
# current_user.logged_in?
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
class Attribute < Field
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
class Serializer
|
|
3
|
+
module Attributes
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
included do
|
|
7
|
+
with_options instance_writer: false, instance_reader: false do |serializer|
|
|
8
|
+
serializer.class_attribute :_attributes_data # @api private
|
|
9
|
+
self._attributes_data ||= {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
extend ActiveSupport::Autoload
|
|
13
|
+
autoload :Attribute
|
|
14
|
+
|
|
15
|
+
# Return the +attributes+ of +object+ as presented
|
|
16
|
+
# by the serializer.
|
|
17
|
+
def attributes(requested_attrs = nil, reload = false)
|
|
18
|
+
@attributes = nil if reload
|
|
19
|
+
@attributes ||= self.class._attributes_data.each_with_object({}) do |(key, attr), hash|
|
|
20
|
+
next if attr.excluded?(self)
|
|
21
|
+
next unless requested_attrs.nil? || requested_attrs.include?(key)
|
|
22
|
+
hash[key] = attr.value(self)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
module ClassMethods
|
|
28
|
+
def inherited(base)
|
|
29
|
+
super
|
|
30
|
+
base._attributes_data = _attributes_data.dup
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @example
|
|
34
|
+
# class AdminAuthorSerializer < ActiveModel::Serializer
|
|
35
|
+
# attributes :id, :name, :recent_edits
|
|
36
|
+
def attributes(*attrs)
|
|
37
|
+
attrs = attrs.first if attrs.first.class == Array
|
|
38
|
+
|
|
39
|
+
attrs.each do |attr|
|
|
40
|
+
attribute(attr)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @example
|
|
45
|
+
# class AdminAuthorSerializer < ActiveModel::Serializer
|
|
46
|
+
# attributes :id, :recent_edits
|
|
47
|
+
# attribute :name, key: :title
|
|
48
|
+
#
|
|
49
|
+
# attribute :full_name do
|
|
50
|
+
# "#{object.first_name} #{object.last_name}"
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# def recent_edits
|
|
54
|
+
# object.edits.last(5)
|
|
55
|
+
# end
|
|
56
|
+
def attribute(attr, options = {}, &block)
|
|
57
|
+
key = options.fetch(:key, attr)
|
|
58
|
+
_attributes_data[key] = Attribute.new(attr, options, block)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @api private
|
|
62
|
+
# keys of attributes
|
|
63
|
+
# @see Serializer::attribute
|
|
64
|
+
def _attributes
|
|
65
|
+
_attributes_data.keys
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @api private
|
|
69
|
+
# maps attribute value to explict key name
|
|
70
|
+
# @see Serializer::attribute
|
|
71
|
+
# @see FragmentCache#fragment_serializer
|
|
72
|
+
def _attributes_keys
|
|
73
|
+
_attributes_data
|
|
74
|
+
.each_with_object({}) do |(key, attr), hash|
|
|
75
|
+
next if key == attr.name
|
|
76
|
+
hash[attr.name] = { key: key }
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|