active_model_serializers 0.8.3 → 0.10.8
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 +5 -5
- data/.github/ISSUE_TEMPLATE.md +29 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +105 -0
- data/.simplecov +110 -0
- data/.travis.yml +50 -24
- data/CHANGELOG.md +650 -6
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +105 -0
- data/Gemfile +69 -1
- data/{MIT-LICENSE.txt → MIT-LICENSE} +3 -2
- data/README.md +195 -545
- data/Rakefile +64 -8
- data/active_model_serializers.gemspec +62 -23
- data/appveyor.yml +28 -0
- data/bin/bench +171 -0
- data/bin/bench_regression +316 -0
- data/bin/rubocop +38 -0
- data/bin/serve_benchmark +39 -0
- data/docs/README.md +41 -0
- data/docs/STYLE.md +58 -0
- data/docs/general/adapters.md +269 -0
- data/docs/general/caching.md +58 -0
- data/docs/general/configuration_options.md +185 -0
- data/docs/general/deserialization.md +100 -0
- data/docs/general/fields.md +31 -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 +21 -0
- data/docs/general/rendering.md +293 -0
- data/docs/general/serializers.md +495 -0
- data/docs/how-open-source-maintained.jpg +0 -0
- data/docs/howto/add_pagination_links.md +138 -0
- data/docs/howto/add_relationship_links.md +140 -0
- data/docs/howto/add_root_key.md +62 -0
- data/docs/howto/grape_integration.md +42 -0
- data/docs/howto/outside_controller_use.md +66 -0
- data/docs/howto/passing_arbitrary_options.md +27 -0
- data/docs/howto/serialize_poro.md +73 -0
- data/docs/howto/test.md +154 -0
- data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
- data/docs/integrations/ember-and-json-api.md +147 -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 +43 -38
- 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 +18 -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 +12 -0
- data/lib/active_model/serializer/association.rb +71 -0
- data/lib/active_model/serializer/attribute.rb +25 -0
- data/lib/active_model/serializer/belongs_to_reflection.rb +11 -0
- data/lib/active_model/serializer/collection_serializer.rb +88 -0
- data/lib/active_model/serializer/concerns/caching.rb +300 -0
- data/lib/active_model/serializer/error_serializer.rb +14 -0
- data/lib/active_model/serializer/errors_serializer.rb +32 -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 +7 -0
- data/lib/active_model/serializer/lazy_association.rb +96 -0
- data/lib/active_model/serializer/link.rb +21 -0
- data/lib/active_model/serializer/lint.rb +150 -0
- data/lib/active_model/serializer/null.rb +17 -0
- data/lib/active_model/serializer/reflection.rb +210 -0
- data/lib/active_model/{serializers → serializer}/version.rb +1 -1
- data/lib/active_model/serializer.rb +343 -442
- data/lib/active_model_serializers/adapter/attributes.rb +13 -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 +88 -0
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +104 -0
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +66 -0
- data/lib/active_model_serializers/adapter/json_api.rb +533 -0
- data/lib/active_model_serializers/adapter/null.rb +9 -0
- data/lib/active_model_serializers/adapter.rb +98 -0
- data/lib/active_model_serializers/callbacks.rb +55 -0
- data/lib/active_model_serializers/deprecate.rb +54 -0
- data/lib/active_model_serializers/deserialization.rb +15 -0
- data/lib/active_model_serializers/json_pointer.rb +14 -0
- data/lib/active_model_serializers/logging.rb +122 -0
- data/lib/active_model_serializers/lookup_chain.rb +80 -0
- data/lib/active_model_serializers/model.rb +130 -0
- data/lib/active_model_serializers/railtie.rb +50 -0
- data/lib/active_model_serializers/register_jsonapi_renderer.rb +78 -0
- data/lib/active_model_serializers/serializable_resource.rb +82 -0
- data/lib/active_model_serializers/serialization_context.rb +39 -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 +47 -81
- 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 +16 -0
- data/lib/grape/formatters/active_model_serializers.rb +32 -0
- data/lib/grape/helpers/active_model_serializers.rb +17 -0
- data/lib/tasks/rubocop.rake +53 -0
- data/test/action_controller/adapter_selector_test.rb +62 -0
- data/test/action_controller/explicit_serializer_test.rb +135 -0
- data/test/action_controller/json/include_test.rb +246 -0
- data/test/action_controller/json_api/deserialization_test.rb +112 -0
- data/test/action_controller/json_api/errors_test.rb +40 -0
- data/test/action_controller/json_api/fields_test.rb +66 -0
- data/test/action_controller/json_api/linked_test.rb +202 -0
- data/test/action_controller/json_api/pagination_test.rb +124 -0
- data/test/action_controller/json_api/transform_test.rb +189 -0
- data/test/action_controller/lookup_proc_test.rb +49 -0
- data/test/action_controller/namespace_lookup_test.rb +232 -0
- data/test/action_controller/serialization_scope_name_test.rb +235 -0
- data/test/action_controller/serialization_test.rb +478 -0
- data/test/active_model_serializers/adapter_for_test.rb +208 -0
- data/test/active_model_serializers/json_pointer_test.rb +22 -0
- data/test/active_model_serializers/logging_test.rb +77 -0
- data/test/active_model_serializers/model_test.rb +142 -0
- data/test/active_model_serializers/railtie_test_isolated.rb +68 -0
- data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
- data/test/active_model_serializers/serialization_context_test_isolated.rb +71 -0
- data/test/active_model_serializers/test/schema_test.rb +131 -0
- data/test/active_model_serializers/test/serializer_test.rb +62 -0
- data/test/active_record_test.rb +9 -0
- data/test/adapter/attributes_test.rb +40 -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 +104 -0
- data/test/adapter/json/has_many_test.rb +53 -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 +96 -0
- data/test/adapter/json_api/errors_test.rb +76 -0
- data/test/adapter/json_api/fields_test.rb +96 -0
- data/test/adapter/json_api/has_many_explicit_serializer_test.rb +96 -0
- data/test/adapter/json_api/has_many_test.rb +173 -0
- data/test/adapter/json_api/has_one_test.rb +80 -0
- data/test/adapter/json_api/include_data_if_sideloaded_test.rb +213 -0
- data/test/adapter/json_api/json_api_test.rb +33 -0
- data/test/adapter/json_api/linked_test.rb +413 -0
- data/test/adapter/json_api/links_test.rb +110 -0
- data/test/adapter/json_api/pagination_links_test.rb +206 -0
- data/test/adapter/json_api/parse_test.rb +137 -0
- data/test/adapter/json_api/relationship_test.rb +397 -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 +512 -0
- data/test/adapter/json_api/type_test.rb +193 -0
- data/test/adapter/json_test.rb +46 -0
- data/test/adapter/null_test.rb +22 -0
- data/test/adapter/polymorphic_test.rb +218 -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_active_record.rb +81 -0
- data/test/benchmark/bm_adapter.rb +38 -0
- data/test/benchmark/bm_caching.rb +119 -0
- data/test/benchmark/bm_lookup_chain.rb +83 -0
- data/test/benchmark/bm_transform.rb +45 -0
- data/test/benchmark/config.ru +3 -0
- data/test/benchmark/controllers.rb +83 -0
- data/test/benchmark/fixtures.rb +219 -0
- data/test/cache_test.rb +651 -0
- data/test/collection_serializer_test.rb +127 -0
- data/test/fixtures/active_record.rb +113 -0
- data/test/fixtures/poro.rb +225 -0
- data/test/generators/scaffold_controller_generator_test.rb +24 -0
- data/test/generators/serializer_generator_test.rb +75 -0
- data/test/grape_test.rb +196 -0
- data/test/lint_test.rb +49 -0
- data/test/logger_test.rb +20 -0
- data/test/poro_test.rb +9 -0
- data/test/serializable_resource_test.rb +79 -0
- data/test/serializers/association_macros_test.rb +37 -0
- data/test/serializers/associations_test.rb +518 -0
- data/test/serializers/attribute_test.rb +153 -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 +202 -0
- data/test/serializers/options_test.rb +32 -0
- data/test/serializers/read_attribute_for_serialization_test.rb +79 -0
- data/test/serializers/reflection_test.rb +479 -0
- data/test/serializers/root_test.rb +21 -0
- data/test/serializers/serialization_test.rb +55 -0
- data/test/serializers/serializer_for_test.rb +136 -0
- data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
- data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +6 -0
- data/test/support/isolated_unit.rb +84 -0
- data/test/support/rails5_shims.rb +53 -0
- data/test/support/rails_app.rb +38 -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 +79 -0
- data/test/test_helper.rb +59 -21
- metadata +529 -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_model/serializer/associations.rb +0 -233
- 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,515 +1,416 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require '
|
|
4
|
-
require '
|
|
5
|
-
|
|
1
|
+
require 'thread_safe'
|
|
2
|
+
require 'jsonapi/include_directive'
|
|
3
|
+
require 'active_model/serializer/collection_serializer'
|
|
4
|
+
require 'active_model/serializer/array_serializer'
|
|
5
|
+
require 'active_model/serializer/error_serializer'
|
|
6
|
+
require 'active_model/serializer/errors_serializer'
|
|
7
|
+
require 'active_model/serializer/concerns/caching'
|
|
8
|
+
require 'active_model/serializer/fieldset'
|
|
9
|
+
require 'active_model/serializer/lint'
|
|
10
|
+
|
|
11
|
+
# ActiveModel::Serializer is an abstract class that is
|
|
12
|
+
# reified when subclassed to decorate a resource.
|
|
6
13
|
module ActiveModel
|
|
7
|
-
# Active Model Serializer
|
|
8
|
-
#
|
|
9
|
-
# Provides a basic serializer implementation that allows you to easily
|
|
10
|
-
# control how a given object is going to be serialized. On initialization,
|
|
11
|
-
# it expects two objects as arguments, a resource and options. For example,
|
|
12
|
-
# one may do in a controller:
|
|
13
|
-
#
|
|
14
|
-
# PostSerializer.new(@post, :scope => current_user).to_json
|
|
15
|
-
#
|
|
16
|
-
# The object to be serialized is the +@post+ and the current user is passed
|
|
17
|
-
# in for authorization purposes.
|
|
18
|
-
#
|
|
19
|
-
# We use the scope to check if a given attribute should be serialized or not.
|
|
20
|
-
# For example, some attributes may only be returned if +current_user+ is the
|
|
21
|
-
# author of the post:
|
|
22
|
-
#
|
|
23
|
-
# class PostSerializer < ActiveModel::Serializer
|
|
24
|
-
# attributes :title, :body
|
|
25
|
-
# has_many :comments
|
|
26
|
-
#
|
|
27
|
-
# private
|
|
28
|
-
#
|
|
29
|
-
# def attributes
|
|
30
|
-
# hash = super
|
|
31
|
-
# hash.merge!(:email => post.email) if author?
|
|
32
|
-
# hash
|
|
33
|
-
# end
|
|
34
|
-
#
|
|
35
|
-
# def author?
|
|
36
|
-
# post.author == scope
|
|
37
|
-
# end
|
|
38
|
-
# end
|
|
39
|
-
#
|
|
40
14
|
class Serializer
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
15
|
+
undef_method :select, :display # These IO methods, which are mixed into Kernel,
|
|
16
|
+
# sometimes conflict with attribute names. We don't need these IO methods.
|
|
17
|
+
|
|
18
|
+
# @see #serializable_hash for more details on these valid keys.
|
|
19
|
+
SERIALIZABLE_HASH_VALID_KEYS = [:only, :except, :methods, :include, :root].freeze
|
|
20
|
+
extend ActiveSupport::Autoload
|
|
21
|
+
eager_autoload do
|
|
22
|
+
autoload :Adapter
|
|
23
|
+
autoload :Null
|
|
24
|
+
autoload :Attribute
|
|
25
|
+
autoload :Link
|
|
26
|
+
autoload :Association
|
|
27
|
+
autoload :Reflection
|
|
28
|
+
autoload :BelongsToReflection
|
|
29
|
+
autoload :HasOneReflection
|
|
30
|
+
autoload :HasManyReflection
|
|
31
|
+
end
|
|
32
|
+
include ActiveSupport::Configurable
|
|
33
|
+
include Caching
|
|
34
|
+
|
|
35
|
+
# @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
|
|
36
|
+
# @return [ActiveModel::Serializer]
|
|
37
|
+
# Preferentially returns
|
|
38
|
+
# 1. resource.serializer_class
|
|
39
|
+
# 2. ArraySerializer when resource is a collection
|
|
40
|
+
# 3. options[:serializer]
|
|
41
|
+
# 4. lookup serializer when resource is a Class
|
|
42
|
+
def self.serializer_for(resource_or_class, options = {})
|
|
43
|
+
if resource_or_class.respond_to?(:serializer_class)
|
|
44
|
+
resource_or_class.serializer_class
|
|
45
|
+
elsif resource_or_class.respond_to?(:to_ary)
|
|
46
|
+
config.collection_serializer
|
|
47
|
+
else
|
|
48
|
+
resource_class = resource_or_class.class == Class ? resource_or_class : resource_or_class.class
|
|
49
|
+
options.fetch(:serializer) { get_serializer_for(resource_class, options[:namespace]) }
|
|
55
50
|
end
|
|
56
51
|
end
|
|
57
52
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class_attribute :_root
|
|
65
|
-
class_attribute :_embed
|
|
66
|
-
self._embed = :objects
|
|
67
|
-
class_attribute :_root_embed
|
|
68
|
-
|
|
69
|
-
class_attribute :cache
|
|
70
|
-
class_attribute :perform_caching
|
|
71
|
-
|
|
53
|
+
# @see ActiveModelSerializers::Adapter.lookup
|
|
54
|
+
# Deprecated
|
|
55
|
+
def self.adapter
|
|
56
|
+
ActiveModelSerializers::Adapter.lookup(config.adapter)
|
|
57
|
+
end
|
|
72
58
|
class << self
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Define attributes to be used in the serialization.
|
|
79
|
-
def attributes(*attrs)
|
|
80
|
-
|
|
81
|
-
self._attributes = _attributes.dup
|
|
82
|
-
|
|
83
|
-
attrs.each do |attr|
|
|
84
|
-
if Hash === attr
|
|
85
|
-
attr.each {|attr_real, key| attribute attr_real, :key => key }
|
|
86
|
-
else
|
|
87
|
-
attribute attr
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def attribute(attr, options={})
|
|
93
|
-
self._attributes = _attributes.merge(attr.is_a?(Hash) ? attr : {attr => options[:key] || attr.to_s.gsub(/\?$/, '').to_sym})
|
|
94
|
-
|
|
95
|
-
attr = attr.keys[0] if attr.is_a? Hash
|
|
96
|
-
|
|
97
|
-
unless method_defined?(attr)
|
|
98
|
-
define_method attr do
|
|
99
|
-
object.read_attribute_for_serialization(attr.to_sym)
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
define_include_method attr
|
|
104
|
-
|
|
105
|
-
# protect inheritance chains and open classes
|
|
106
|
-
# if a serializer inherits from another OR
|
|
107
|
-
# attributes are added later in a classes lifecycle
|
|
108
|
-
# poison the cache
|
|
109
|
-
define_method :_fast_attributes do
|
|
110
|
-
raise NameError
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def associate(klass, attrs) #:nodoc:
|
|
116
|
-
options = attrs.extract_options!
|
|
117
|
-
self._associations = _associations.dup
|
|
118
|
-
|
|
119
|
-
attrs.each do |attr|
|
|
120
|
-
unless method_defined?(attr)
|
|
121
|
-
define_method attr do
|
|
122
|
-
object.send attr
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
define_include_method attr
|
|
127
|
-
|
|
128
|
-
self._associations[attr] = klass.refine(attr, options)
|
|
129
|
-
end
|
|
130
|
-
end
|
|
59
|
+
extend ActiveModelSerializers::Deprecate
|
|
60
|
+
deprecate :adapter, 'ActiveModelSerializers::Adapter.configured_adapter'
|
|
61
|
+
end
|
|
131
62
|
|
|
132
|
-
|
|
133
|
-
|
|
63
|
+
# @api private
|
|
64
|
+
def self.serializer_lookup_chain_for(klass, namespace = nil)
|
|
65
|
+
lookups = ActiveModelSerializers.config.serializer_lookup_chain
|
|
66
|
+
Array[*lookups].flat_map do |lookup|
|
|
67
|
+
lookup.call(klass, self, namespace)
|
|
68
|
+
end.compact
|
|
69
|
+
end
|
|
134
70
|
|
|
135
|
-
|
|
71
|
+
# Used to cache serializer name => serializer class
|
|
72
|
+
# when looked up by Serializer.get_serializer_for.
|
|
73
|
+
def self.serializers_cache
|
|
74
|
+
@serializers_cache ||= ThreadSafe::Cache.new
|
|
75
|
+
end
|
|
136
76
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
77
|
+
# @api private
|
|
78
|
+
# Find a serializer from a class and caches the lookup.
|
|
79
|
+
# Preferentially returns:
|
|
80
|
+
# 1. class name appended with "Serializer"
|
|
81
|
+
# 2. try again with superclass, if present
|
|
82
|
+
# 3. nil
|
|
83
|
+
def self.get_serializer_for(klass, namespace = nil)
|
|
84
|
+
return nil unless config.serializer_lookup_enabled
|
|
85
|
+
|
|
86
|
+
cache_key = ActiveSupport::Cache.expand_cache_key(klass, namespace)
|
|
87
|
+
serializers_cache.fetch_or_store(cache_key) do
|
|
88
|
+
# NOTE(beauby): When we drop 1.9.3 support we can lazify the map for perfs.
|
|
89
|
+
lookup_chain = serializer_lookup_chain_for(klass, namespace)
|
|
90
|
+
serializer_class = lookup_chain.map(&:safe_constantize).find { |x| x && x < ActiveModel::Serializer }
|
|
91
|
+
|
|
92
|
+
if serializer_class
|
|
93
|
+
serializer_class
|
|
94
|
+
elsif klass.superclass
|
|
95
|
+
get_serializer_for(klass.superclass)
|
|
96
|
+
else
|
|
97
|
+
nil # No serializer found
|
|
141
98
|
end
|
|
142
99
|
end
|
|
100
|
+
end
|
|
143
101
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
# Defines an association in the object should be rendered.
|
|
155
|
-
#
|
|
156
|
-
# The serializer object should implement the association name
|
|
157
|
-
# as a method which should return an object when invoked. If a method
|
|
158
|
-
# with the association name does not exist, the association name is
|
|
159
|
-
# dispatched to the serialized object.
|
|
160
|
-
def has_one(*attrs)
|
|
161
|
-
associate(Associations::HasOne, attrs)
|
|
102
|
+
# @api private
|
|
103
|
+
def self.include_directive_from_options(options)
|
|
104
|
+
if options[:include_directive]
|
|
105
|
+
options[:include_directive]
|
|
106
|
+
elsif options[:include]
|
|
107
|
+
JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
|
|
108
|
+
else
|
|
109
|
+
ActiveModelSerializers.default_include_directive
|
|
162
110
|
end
|
|
111
|
+
end
|
|
163
112
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
#
|
|
169
|
-
# The +attributes+ hash looks like this:
|
|
170
|
-
#
|
|
171
|
-
# { :name => :string, :age => :integer }
|
|
172
|
-
#
|
|
173
|
-
# The +associations+ hash looks like this:
|
|
174
|
-
# { :posts => { :has_many => :posts } }
|
|
175
|
-
#
|
|
176
|
-
# If :key is used:
|
|
177
|
-
#
|
|
178
|
-
# class PostsSerializer < ActiveModel::Serializer
|
|
179
|
-
# has_many :posts, :key => :my_posts
|
|
180
|
-
# end
|
|
181
|
-
#
|
|
182
|
-
# the hash looks like this:
|
|
183
|
-
#
|
|
184
|
-
# { :my_posts => { :has_many => :posts }
|
|
185
|
-
#
|
|
186
|
-
# This information is extracted from the serializer's model class,
|
|
187
|
-
# which is provided by +SerializerClass.model_class+.
|
|
188
|
-
#
|
|
189
|
-
# The schema method uses the +columns_hash+ and +reflect_on_association+
|
|
190
|
-
# methods, provided by default by ActiveRecord. You can implement these
|
|
191
|
-
# methods on your custom models if you want the serializer's schema method
|
|
192
|
-
# to work.
|
|
193
|
-
#
|
|
194
|
-
# TODO: This is currently coupled to Active Record. We need to
|
|
195
|
-
# figure out a way to decouple those two.
|
|
196
|
-
def schema
|
|
197
|
-
klass = model_class
|
|
198
|
-
columns = klass.columns_hash
|
|
199
|
-
|
|
200
|
-
attrs = {}
|
|
201
|
-
_attributes.each do |name, key|
|
|
202
|
-
if column = columns[name.to_s]
|
|
203
|
-
attrs[key] = column.type
|
|
204
|
-
else
|
|
205
|
-
# Computed attribute (method on serializer or model). We cannot
|
|
206
|
-
# infer the type, so we put nil, unless specified in the attribute declaration
|
|
207
|
-
if name != key
|
|
208
|
-
attrs[name] = key
|
|
209
|
-
else
|
|
210
|
-
attrs[key] = nil
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
associations = {}
|
|
216
|
-
_associations.each do |attr, association_class|
|
|
217
|
-
association = association_class.new(attr, self)
|
|
218
|
-
|
|
219
|
-
if model_association = klass.reflect_on_association(association.name)
|
|
220
|
-
# Real association.
|
|
221
|
-
associations[association.key] = { model_association.macro => model_association.name }
|
|
222
|
-
else
|
|
223
|
-
# Computed association. We could infer has_many vs. has_one from
|
|
224
|
-
# the association class, but that would make it different from
|
|
225
|
-
# real associations, which read has_one vs. belongs_to from the
|
|
226
|
-
# model.
|
|
227
|
-
associations[association.key] = nil
|
|
228
|
-
end
|
|
229
|
-
end
|
|
113
|
+
# @api private
|
|
114
|
+
def self.serialization_adapter_instance
|
|
115
|
+
@serialization_adapter_instance ||= ActiveModelSerializers::Adapter::Attributes
|
|
116
|
+
end
|
|
230
117
|
|
|
231
|
-
|
|
232
|
-
|
|
118
|
+
# Preferred interface is ActiveModelSerializers.config
|
|
119
|
+
# BEGIN DEFAULT CONFIGURATION
|
|
120
|
+
config.collection_serializer = ActiveModel::Serializer::CollectionSerializer
|
|
121
|
+
config.serializer_lookup_enabled = true
|
|
233
122
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
123
|
+
# @deprecated Use {#config.collection_serializer=} instead of this. Is
|
|
124
|
+
# compatibility layer for ArraySerializer.
|
|
125
|
+
def config.array_serializer=(collection_serializer)
|
|
126
|
+
self.collection_serializer = collection_serializer
|
|
127
|
+
end
|
|
238
128
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
#
|
|
245
|
-
def embed(type, options={})
|
|
246
|
-
self._embed = type
|
|
247
|
-
self._root_embed = true if options[:include]
|
|
248
|
-
end
|
|
129
|
+
# @deprecated Use {#config.collection_serializer} instead of this. Is
|
|
130
|
+
# compatibility layer for ArraySerializer.
|
|
131
|
+
def config.array_serializer
|
|
132
|
+
collection_serializer
|
|
133
|
+
end
|
|
249
134
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
135
|
+
config.default_includes = '*'
|
|
136
|
+
config.adapter = :attributes
|
|
137
|
+
config.key_transform = nil
|
|
138
|
+
config.jsonapi_pagination_links_enabled = true
|
|
139
|
+
config.jsonapi_resource_type = :plural
|
|
140
|
+
config.jsonapi_namespace_separator = '-'.freeze
|
|
141
|
+
config.jsonapi_version = '1.0'
|
|
142
|
+
config.jsonapi_toplevel_meta = {}
|
|
143
|
+
# Make JSON API top-level jsonapi member opt-in
|
|
144
|
+
# ref: http://jsonapi.org/format/#document-top-level
|
|
145
|
+
config.jsonapi_include_toplevel_object = false
|
|
146
|
+
config.jsonapi_use_foreign_key_on_belongs_to_relationship = false
|
|
147
|
+
config.include_data_default = true
|
|
148
|
+
|
|
149
|
+
# For configuring how serializers are found.
|
|
150
|
+
# This should be an array of procs.
|
|
151
|
+
#
|
|
152
|
+
# The priority of the output is that the first item
|
|
153
|
+
# in the evaluated result array will take precedence
|
|
154
|
+
# over other possible serializer paths.
|
|
155
|
+
#
|
|
156
|
+
# i.e.: First match wins.
|
|
157
|
+
#
|
|
158
|
+
# @example output
|
|
159
|
+
# => [
|
|
160
|
+
# "CustomNamespace::ResourceSerializer",
|
|
161
|
+
# "ParentSerializer::ResourceSerializer",
|
|
162
|
+
# "ResourceNamespace::ResourceSerializer" ,
|
|
163
|
+
# "ResourceSerializer"]
|
|
164
|
+
#
|
|
165
|
+
# If CustomNamespace::ResourceSerializer exists, it will be used
|
|
166
|
+
# for serialization
|
|
167
|
+
config.serializer_lookup_chain = ActiveModelSerializers::LookupChain::DEFAULT.dup
|
|
281
168
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
options[:url_options] = controller.url_options
|
|
169
|
+
config.schema_path = 'test/support/schemas'
|
|
170
|
+
# END DEFAULT CONFIGURATION
|
|
285
171
|
|
|
286
|
-
|
|
287
|
-
|
|
172
|
+
with_options instance_writer: false, instance_reader: false do |serializer|
|
|
173
|
+
serializer.class_attribute :_attributes_data # @api private
|
|
174
|
+
self._attributes_data ||= {}
|
|
175
|
+
end
|
|
176
|
+
with_options instance_writer: false, instance_reader: true do |serializer|
|
|
177
|
+
serializer.class_attribute :_reflections
|
|
178
|
+
self._reflections ||= {}
|
|
179
|
+
serializer.class_attribute :_links # @api private
|
|
180
|
+
self._links ||= {}
|
|
181
|
+
serializer.class_attribute :_meta # @api private
|
|
182
|
+
serializer.class_attribute :_type # @api private
|
|
288
183
|
end
|
|
289
184
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
185
|
+
def self.inherited(base)
|
|
186
|
+
super
|
|
187
|
+
base._attributes_data = _attributes_data.dup
|
|
188
|
+
base._reflections = _reflections.dup
|
|
189
|
+
base._links = _links.dup
|
|
190
|
+
end
|
|
294
191
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
end
|
|
300
|
-
end
|
|
192
|
+
# @return [Array<Symbol>] Key names of declared attributes
|
|
193
|
+
# @see Serializer::attribute
|
|
194
|
+
def self._attributes
|
|
195
|
+
_attributes_data.keys
|
|
301
196
|
end
|
|
302
197
|
|
|
303
|
-
|
|
304
|
-
return false if self._root == false
|
|
198
|
+
# BEGIN SERIALIZER MACROS
|
|
305
199
|
|
|
306
|
-
|
|
200
|
+
# @example
|
|
201
|
+
# class AdminAuthorSerializer < ActiveModel::Serializer
|
|
202
|
+
# attributes :id, :name, :recent_edits
|
|
203
|
+
def self.attributes(*attrs)
|
|
204
|
+
attrs = attrs.first if attrs.first.class == Array
|
|
307
205
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
else
|
|
311
|
-
self._root || class_name
|
|
206
|
+
attrs.each do |attr|
|
|
207
|
+
attribute(attr)
|
|
312
208
|
end
|
|
313
209
|
end
|
|
314
210
|
|
|
315
|
-
|
|
316
|
-
|
|
211
|
+
# @example
|
|
212
|
+
# class AdminAuthorSerializer < ActiveModel::Serializer
|
|
213
|
+
# attributes :id, :recent_edits
|
|
214
|
+
# attribute :name, key: :title
|
|
215
|
+
#
|
|
216
|
+
# attribute :full_name do
|
|
217
|
+
# "#{object.first_name} #{object.last_name}"
|
|
218
|
+
# end
|
|
219
|
+
#
|
|
220
|
+
# def recent_edits
|
|
221
|
+
# object.edits.last(5)
|
|
222
|
+
# end
|
|
223
|
+
def self.attribute(attr, options = {}, &block)
|
|
224
|
+
key = options.fetch(:key, attr)
|
|
225
|
+
_attributes_data[key] = Attribute.new(attr, options, block)
|
|
317
226
|
end
|
|
318
227
|
|
|
319
|
-
|
|
320
|
-
|
|
228
|
+
# @param [Symbol] name of the association
|
|
229
|
+
# @param [Hash<Symbol => any>] options for the reflection
|
|
230
|
+
# @return [void]
|
|
231
|
+
#
|
|
232
|
+
# @example
|
|
233
|
+
# has_many :comments, serializer: CommentSummarySerializer
|
|
234
|
+
#
|
|
235
|
+
def self.has_many(name, options = {}, &block) # rubocop:disable Style/PredicateName
|
|
236
|
+
associate(HasManyReflection.new(name, options, block))
|
|
321
237
|
end
|
|
322
238
|
|
|
323
|
-
|
|
324
|
-
|
|
239
|
+
# @param [Symbol] name of the association
|
|
240
|
+
# @param [Hash<Symbol => any>] options for the reflection
|
|
241
|
+
# @return [void]
|
|
242
|
+
#
|
|
243
|
+
# @example
|
|
244
|
+
# belongs_to :author, serializer: AuthorSerializer
|
|
245
|
+
#
|
|
246
|
+
def self.belongs_to(name, options = {}, &block)
|
|
247
|
+
associate(BelongsToReflection.new(name, options, block))
|
|
325
248
|
end
|
|
326
249
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
250
|
+
# @param [Symbol] name of the association
|
|
251
|
+
# @param [Hash<Symbol => any>] options for the reflection
|
|
252
|
+
# @return [void]
|
|
253
|
+
#
|
|
254
|
+
# @example
|
|
255
|
+
# has_one :author, serializer: AuthorSerializer
|
|
256
|
+
#
|
|
257
|
+
def self.has_one(name, options = {}, &block) # rubocop:disable Style/PredicateName
|
|
258
|
+
associate(HasOneReflection.new(name, options, block))
|
|
335
259
|
end
|
|
336
260
|
|
|
337
|
-
#
|
|
338
|
-
#
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
hash.merge!(root => serializable_hash)
|
|
346
|
-
include_meta hash
|
|
347
|
-
hash
|
|
348
|
-
else
|
|
349
|
-
serializable_hash
|
|
350
|
-
end
|
|
261
|
+
# Add reflection and define {name} accessor.
|
|
262
|
+
# @param [ActiveModel::Serializer::Reflection] reflection
|
|
263
|
+
# @return [void]
|
|
264
|
+
#
|
|
265
|
+
# @api private
|
|
266
|
+
def self.associate(reflection)
|
|
267
|
+
key = reflection.options[:key] || reflection.name
|
|
268
|
+
self._reflections[key] = reflection
|
|
351
269
|
end
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
#
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
270
|
+
private_class_method :associate
|
|
271
|
+
|
|
272
|
+
# Define a link on a serializer.
|
|
273
|
+
# @example
|
|
274
|
+
# link(:self) { resource_url(object) }
|
|
275
|
+
# @example
|
|
276
|
+
# link(:self) { "http://example.com/resource/#{object.id}" }
|
|
277
|
+
# @example
|
|
278
|
+
# link :resource, "http://example.com/resource"
|
|
279
|
+
# @example
|
|
280
|
+
# link(:callback, if: :internal?), { "http://example.com/callback" }
|
|
281
|
+
#
|
|
282
|
+
def self.link(name, *args, &block)
|
|
283
|
+
options = args.extract_options!
|
|
284
|
+
# For compatibility with the use case of passing link directly as string argument
|
|
285
|
+
# without block, we are creating a wrapping block
|
|
286
|
+
_links[name] = Link.new(name, options, block || ->(_serializer) { args.first })
|
|
363
287
|
end
|
|
364
288
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
289
|
+
# Set the JSON API meta attribute of a serializer.
|
|
290
|
+
# @example
|
|
291
|
+
# class AdminAuthorSerializer < ActiveModel::Serializer
|
|
292
|
+
# meta { stuff: 'value' }
|
|
293
|
+
# @example
|
|
294
|
+
# meta do
|
|
295
|
+
# { comment_count: object.comments.count }
|
|
296
|
+
# end
|
|
297
|
+
def self.meta(value = nil, &block)
|
|
298
|
+
self._meta = block || value
|
|
369
299
|
end
|
|
370
300
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
# Make sure that if a special options[:hash] was passed in, we generate
|
|
379
|
-
# a new unique values hash and don't clobber the original. If the hash
|
|
380
|
-
# passed in is the same as the current options hash, use the current
|
|
381
|
-
# unique values.
|
|
382
|
-
#
|
|
383
|
-
# TODO: Should passing in a Hash even be public API here?
|
|
384
|
-
unique_values =
|
|
385
|
-
if hash = options[:hash]
|
|
386
|
-
if @options[:hash] == hash
|
|
387
|
-
@options[:unique_values] ||= {}
|
|
388
|
-
else
|
|
389
|
-
{}
|
|
390
|
-
end
|
|
391
|
-
else
|
|
392
|
-
hash = @options[:hash]
|
|
393
|
-
@options[:unique_values] ||= {}
|
|
394
|
-
end
|
|
301
|
+
# Set the JSON API type of a serializer.
|
|
302
|
+
# @example
|
|
303
|
+
# class AdminAuthorSerializer < ActiveModel::Serializer
|
|
304
|
+
# type 'authors'
|
|
305
|
+
def self.type(type)
|
|
306
|
+
self._type = type && type.to_s
|
|
307
|
+
end
|
|
395
308
|
|
|
396
|
-
|
|
397
|
-
value = options[:value]
|
|
309
|
+
# END SERIALIZER MACROS
|
|
398
310
|
|
|
399
|
-
|
|
400
|
-
if @options.key?(:include)
|
|
401
|
-
options[:include] = @options[:include].include?(name)
|
|
402
|
-
elsif @options.include?(:exclude)
|
|
403
|
-
options[:include] = !@options[:exclude].include?(name)
|
|
404
|
-
end
|
|
405
|
-
end
|
|
311
|
+
attr_accessor :object, :root, :scope
|
|
406
312
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
313
|
+
# `scope_name` is set as :current_user by default in the controller.
|
|
314
|
+
# If the instance does not have a method named `scope_name`, it
|
|
315
|
+
# defines the method so that it calls the +scope+.
|
|
316
|
+
def initialize(object, options = {})
|
|
317
|
+
self.object = object
|
|
318
|
+
self.instance_options = options
|
|
319
|
+
self.root = instance_options[:root]
|
|
320
|
+
self.scope = instance_options[:scope]
|
|
415
321
|
|
|
416
|
-
|
|
322
|
+
return if !(scope_name = instance_options[:scope_name]) || respond_to?(scope_name)
|
|
417
323
|
|
|
418
|
-
|
|
419
|
-
|
|
324
|
+
define_singleton_method scope_name, -> { scope }
|
|
325
|
+
end
|
|
420
326
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
elsif association.embed_in_root? && association.embeddable?
|
|
424
|
-
merge_association hash, association.root, association.serializables, unique_values
|
|
425
|
-
end
|
|
426
|
-
elsif association.embed_objects?
|
|
427
|
-
node[association.key] = association.serialize
|
|
428
|
-
end
|
|
327
|
+
def success?
|
|
328
|
+
true
|
|
429
329
|
end
|
|
430
330
|
|
|
431
|
-
#
|
|
432
|
-
#
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
# we want to merge a new list of values.
|
|
440
|
-
def merge_association(hash, key, serializables, unique_values)
|
|
441
|
-
already_serialized = (unique_values[key] ||= {})
|
|
442
|
-
serializable_hashes = (hash[key] ||= [])
|
|
443
|
-
|
|
444
|
-
serializables.each do |serializable|
|
|
445
|
-
unless already_serialized.include? serializable.object
|
|
446
|
-
already_serialized[serializable.object] = true
|
|
447
|
-
serializable_hashes << serializable.serializable_hash
|
|
448
|
-
end
|
|
331
|
+
# Return the +attributes+ of +object+ as presented
|
|
332
|
+
# by the serializer.
|
|
333
|
+
def attributes(requested_attrs = nil, reload = false)
|
|
334
|
+
@attributes = nil if reload
|
|
335
|
+
@attributes ||= self.class._attributes_data.each_with_object({}) do |(key, attr), hash|
|
|
336
|
+
next if attr.excluded?(self)
|
|
337
|
+
next unless requested_attrs.nil? || requested_attrs.include?(key)
|
|
338
|
+
hash[key] = attr.value(self)
|
|
449
339
|
end
|
|
450
340
|
end
|
|
451
341
|
|
|
452
|
-
#
|
|
453
|
-
#
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
342
|
+
# @param [JSONAPI::IncludeDirective] include_directive (defaults to the
|
|
343
|
+
# +default_include_directive+ config value when not provided)
|
|
344
|
+
# @return [Enumerator<Association>]
|
|
345
|
+
def associations(include_directive = ActiveModelSerializers.default_include_directive, include_slice = nil)
|
|
346
|
+
include_slice ||= include_directive
|
|
347
|
+
return Enumerator.new {} unless object
|
|
458
348
|
|
|
459
|
-
|
|
349
|
+
Enumerator.new do |y|
|
|
350
|
+
(self.instance_reflections ||= self.class._reflections.deep_dup).each do |key, reflection|
|
|
351
|
+
next if reflection.excluded?(self)
|
|
352
|
+
next unless include_directive.key?(key)
|
|
460
353
|
|
|
461
|
-
|
|
462
|
-
|
|
354
|
+
association = reflection.build_association(self, instance_options, include_slice)
|
|
355
|
+
y.yield association
|
|
463
356
|
end
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
self.class.class_eval method
|
|
467
|
-
_fast_attributes
|
|
357
|
+
end
|
|
468
358
|
end
|
|
469
359
|
|
|
470
|
-
#
|
|
471
|
-
|
|
472
|
-
|
|
360
|
+
# @return [Hash] containing the attributes and first level
|
|
361
|
+
# associations, similar to how ActiveModel::Serializers::JSON is used
|
|
362
|
+
# in ActiveRecord::Base.
|
|
363
|
+
def serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance)
|
|
364
|
+
adapter_options ||= {}
|
|
365
|
+
options[:include_directive] ||= ActiveModel::Serializer.include_directive_from_options(adapter_options)
|
|
366
|
+
resource = attributes_hash(adapter_options, options, adapter_instance)
|
|
367
|
+
relationships = associations_hash(adapter_options, options, adapter_instance)
|
|
368
|
+
resource.merge(relationships)
|
|
473
369
|
end
|
|
370
|
+
alias to_hash serializable_hash
|
|
371
|
+
alias to_h serializable_hash
|
|
474
372
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
return nil if @object.nil?
|
|
479
|
-
@node = attributes
|
|
480
|
-
include_associations! if _embed
|
|
481
|
-
@node
|
|
373
|
+
# @see #serializable_hash
|
|
374
|
+
def as_json(adapter_opts = nil)
|
|
375
|
+
serializable_hash(adapter_opts)
|
|
482
376
|
end
|
|
483
377
|
|
|
484
|
-
|
|
485
|
-
|
|
378
|
+
# Used by adapter as resource root.
|
|
379
|
+
def json_key
|
|
380
|
+
root || _type || object.class.model_name.to_s.underscore
|
|
486
381
|
end
|
|
487
382
|
|
|
488
|
-
def
|
|
489
|
-
|
|
383
|
+
def read_attribute_for_serialization(attr)
|
|
384
|
+
if respond_to?(attr)
|
|
385
|
+
send(attr)
|
|
386
|
+
else
|
|
387
|
+
object.read_attribute_for_serialization(attr)
|
|
388
|
+
end
|
|
490
389
|
end
|
|
491
390
|
|
|
492
|
-
#
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
391
|
+
# @api private
|
|
392
|
+
def attributes_hash(_adapter_options, options, adapter_instance)
|
|
393
|
+
if self.class.cache_enabled?
|
|
394
|
+
fetch_attributes(options[:fields], options[:cached_attributes] || {}, adapter_instance)
|
|
395
|
+
elsif self.class.fragment_cache_enabled?
|
|
396
|
+
fetch_attributes_fragment(adapter_instance, options[:cached_attributes] || {})
|
|
397
|
+
else
|
|
398
|
+
attributes(options[:fields], true)
|
|
399
|
+
end
|
|
497
400
|
end
|
|
498
|
-
end
|
|
499
|
-
|
|
500
|
-
# DefaultSerializer
|
|
501
|
-
#
|
|
502
|
-
# Provides a constant interface for all items, particularly
|
|
503
|
-
# for ArraySerializer.
|
|
504
|
-
class DefaultSerializer
|
|
505
|
-
attr_reader :object, :options
|
|
506
401
|
|
|
507
|
-
|
|
508
|
-
|
|
402
|
+
# @api private
|
|
403
|
+
def associations_hash(adapter_options, options, adapter_instance)
|
|
404
|
+
include_directive = options.fetch(:include_directive)
|
|
405
|
+
include_slice = options[:include_slice]
|
|
406
|
+
associations(include_directive, include_slice).each_with_object({}) do |association, relationships|
|
|
407
|
+
adapter_opts = adapter_options.merge(include_directive: include_directive[association.key], adapter_instance: adapter_instance)
|
|
408
|
+
relationships[association.key] = association.serializable_hash(adapter_opts, adapter_instance)
|
|
409
|
+
end
|
|
509
410
|
end
|
|
510
411
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
412
|
+
protected
|
|
413
|
+
|
|
414
|
+
attr_accessor :instance_options, :instance_reflections
|
|
514
415
|
end
|
|
515
416
|
end
|