agi_active_model_serializers 0.10.7
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 +7 -0
- data/.github/ISSUE_TEMPLATE.md +29 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- data/.gitignore +35 -0
- data/.rubocop.yml +102 -0
- data/.simplecov +110 -0
- data/.travis.yml +51 -0
- data/CHANGELOG.md +612 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +105 -0
- data/Gemfile +56 -0
- data/MIT-LICENSE +22 -0
- data/README.md +307 -0
- data/Rakefile +103 -0
- data/active_model_serializers.gemspec +63 -0
- data/appveyor.yml +24 -0
- data/bin/bench +171 -0
- data/bin/bench_regression +316 -0
- data/bin/serve_benchmark +39 -0
- data/docs/README.md +41 -0
- data/docs/STYLE.md +58 -0
- data/docs/general/adapters.md +247 -0
- data/docs/general/caching.md +58 -0
- data/docs/general/configuration_options.md +169 -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 +14 -0
- data/docs/general/rendering.md +279 -0
- data/docs/general/serializers.md +461 -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 +137 -0
- data/docs/howto/add_root_key.md +55 -0
- data/docs/howto/grape_integration.md +42 -0
- data/docs/howto/outside_controller_use.md +65 -0
- data/docs/howto/passing_arbitrary_options.md +27 -0
- data/docs/howto/serialize_poro.md +32 -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 +144 -0
- data/docs/integrations/grape.md +19 -0
- data/docs/jsonapi/errors.md +56 -0
- data/docs/jsonapi/schema.md +151 -0
- data/docs/jsonapi/schema/schema.json +366 -0
- data/docs/rfcs/0000-namespace.md +106 -0
- data/docs/rfcs/template.md +15 -0
- data/lib/action_controller/serialization.rb +66 -0
- data/lib/active_model/serializable_resource.rb +11 -0
- data/lib/active_model/serializer.rb +231 -0
- data/lib/active_model/serializer/adapter.rb +24 -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/array_serializer.rb +12 -0
- data/lib/active_model/serializer/association.rb +34 -0
- data/lib/active_model/serializer/attribute.rb +25 -0
- data/lib/active_model/serializer/belongs_to_reflection.rb +7 -0
- data/lib/active_model/serializer/collection_reflection.rb +7 -0
- data/lib/active_model/serializer/collection_serializer.rb +87 -0
- data/lib/active_model/serializer/concerns/associations.rb +102 -0
- data/lib/active_model/serializer/concerns/attributes.rb +82 -0
- data/lib/active_model/serializer/concerns/caching.rb +292 -0
- data/lib/active_model/serializer/concerns/configuration.rb +59 -0
- data/lib/active_model/serializer/concerns/links.rb +35 -0
- data/lib/active_model/serializer/concerns/meta.rb +29 -0
- data/lib/active_model/serializer/concerns/type.rb +25 -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 +7 -0
- data/lib/active_model/serializer/has_one_reflection.rb +7 -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 +163 -0
- data/lib/active_model/serializer/singular_reflection.rb +7 -0
- data/lib/active_model/serializer/version.rb +5 -0
- data/lib/active_model_serializers.rb +53 -0
- data/lib/active_model_serializers/adapter.rb +98 -0
- 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.rb +517 -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 +69 -0
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +63 -0
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +51 -0
- data/lib/active_model_serializers/adapter/null.rb +9 -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 +71 -0
- data/lib/active_model_serializers/railtie.rb +48 -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.rb +7 -0
- data/lib/active_model_serializers/test/schema.rb +138 -0
- data/lib/active_model_serializers/test/serializer.rb +125 -0
- 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 +15 -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/test/action_controller/adapter_selector_test.rb +53 -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 +116 -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 +229 -0
- data/test/action_controller/serialization_test.rb +472 -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 +69 -0
- data/test/active_model_serializers/railtie_test_isolated.rb +63 -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 +43 -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 +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 +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_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 +165 -0
- data/test/adapter/json_api/has_one_test.rb +80 -0
- data/test/adapter/json_api/include_data_if_sideloaded_test.rb +168 -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 +95 -0
- data/test/adapter/json_api/pagination_links_test.rb +193 -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_identifier_test.rb +110 -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 +61 -0
- data/test/adapter/json_test.rb +46 -0
- data/test/adapter/null_test.rb +22 -0
- data/test/adapter/polymorphic_test.rb +171 -0
- data/test/adapter_test.rb +67 -0
- data/test/array_serializer_test.rb +22 -0
- 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 +595 -0
- data/test/collection_serializer_test.rb +123 -0
- data/test/fixtures/active_record.rb +113 -0
- data/test/fixtures/poro.rb +232 -0
- data/test/generators/scaffold_controller_generator_test.rb +24 -0
- data/test/generators/serializer_generator_test.rb +74 -0
- data/test/grape_test.rb +178 -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 +383 -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/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 +82 -0
- data/test/support/rails5_shims.rb +53 -0
- data/test/support/rails_app.rb +36 -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 +71 -0
- data/test/test_helper.rb +58 -0
- metadata +602 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
- Start Date: (2015-10-29)
|
|
2
|
+
- RFC PR: https://github.com/rails-api/active_model_serializers/pull/1310
|
|
3
|
+
- ActiveModelSerializers Issue: https://github.com/rails-api/active_model_serializers/issues/1298
|
|
4
|
+
|
|
5
|
+
# Summary
|
|
6
|
+
|
|
7
|
+
Provide a consistent API for the user of the AMS.
|
|
8
|
+
|
|
9
|
+
# Motivation
|
|
10
|
+
|
|
11
|
+
The actual public API is defined under `ActiveModelSerializers`,
|
|
12
|
+
`ActiveModel::Serializer` and `ActiveModel`.
|
|
13
|
+
|
|
14
|
+
At the `ActiveModel::Serializer` we have:
|
|
15
|
+
|
|
16
|
+
- `ActiveModel::Serializer.config`
|
|
17
|
+
- `ActiveModel::Serializer`
|
|
18
|
+
|
|
19
|
+
At the `ActiveModelSerializers` we have:
|
|
20
|
+
|
|
21
|
+
- `ActiveModelSerializers::Model`
|
|
22
|
+
- `ActiveModelSerializers.logger`
|
|
23
|
+
|
|
24
|
+
At `ActiveModel` we have:
|
|
25
|
+
|
|
26
|
+
- `ActiveModel::SerializableResource`
|
|
27
|
+
|
|
28
|
+
The idea here is to provide a single namespace `ActiveModelSerializers` to the user.
|
|
29
|
+
Following the same idea we have on other gems like
|
|
30
|
+
[Devise](https://github.com/plataformatec/devise/blob/e9c82472ffe7c43a448945f77e034a0e47dde0bb/lib/devise.rb),
|
|
31
|
+
[Refile](https://github.com/refile/refile/blob/6b24c293d044862dafbf1bfa4606672a64903aa2/lib/refile.rb) and
|
|
32
|
+
[Active Job](https://github.com/rails/rails/blob/30bacc26f8f258b39e12f63fe52389a968d9c1ea/activejob/lib/active_job.rb)
|
|
33
|
+
for example.
|
|
34
|
+
|
|
35
|
+
This way we are clarifing the boundaries of
|
|
36
|
+
[ActiveModelSerializers and Rails](https://github.com/rails-api/active_model_serializers/blob/master/CHANGELOG.md#prehistory)
|
|
37
|
+
and make clear that the `ActiveModel::Serializer` class is no longer the primary
|
|
38
|
+
behavior of the ActiveModelSerializers.
|
|
39
|
+
|
|
40
|
+
# Detailed design
|
|
41
|
+
|
|
42
|
+
## New classes and modules organization
|
|
43
|
+
|
|
44
|
+
Since this will be a big change we can do this on baby steps, read small pull requests. A
|
|
45
|
+
possible approach is:
|
|
46
|
+
|
|
47
|
+
- All new code will be in `lib/active_model_serializers/` using
|
|
48
|
+
the module namespace `ActiveModelSerializers`.
|
|
49
|
+
- Move all content under `ActiveModel::Serializer` to be under
|
|
50
|
+
`ActiveModelSerializers`, the adapter is on this steps;
|
|
51
|
+
- Move all content under `ActiveModel` to be under `ActiveModelSerializers`,
|
|
52
|
+
the `SerializableResource` is on this step;
|
|
53
|
+
- Change all public API that doesn't make sense, keeping in mind only to keep
|
|
54
|
+
this in the same namespace
|
|
55
|
+
- Update the README;
|
|
56
|
+
- Update the docs;
|
|
57
|
+
|
|
58
|
+
The following table represents the current and the desired classes and modules
|
|
59
|
+
at the first moment.
|
|
60
|
+
|
|
61
|
+
| Current | Desired | Notes |
|
|
62
|
+
|--------------------------------------------------------|--------------------------------------------------|--------------------|
|
|
63
|
+
| `ActiveModelSerializers` and `ActiveModel::Serializer` | `ActiveModelSerializers` | The main namespace |
|
|
64
|
+
| `ActiveModelSerializers.logger` | `ActiveModelSerializers.logger` ||
|
|
65
|
+
| `ActiveModelSerializers::Model` | `ActiveModelSerializers::Model` ||
|
|
66
|
+
| `ActiveModel::SerializableResource` | `ActiveModelSerializers::SerializableResource` ||
|
|
67
|
+
| `ActiveModel::Serializer` | `ActiveModelSerializers::Serializer` | The name can be discussed in a future pull request. For example, we can rename this to `Resource` [following this idea](https://github.com/rails-api/active_model_serializers/pull/1301/files#r42963185) more info about naming in the next section|
|
|
68
|
+
| `ActiveModel::Serializer.config` | `ActiveModelSerializers.config` ||
|
|
69
|
+
|
|
70
|
+
## Renaming of class and modules
|
|
71
|
+
|
|
72
|
+
When moving some content to the new namespace we can find some names that does
|
|
73
|
+
not make much sense like `ActiveModel::Serializer::Adapter::JsonApi`.
|
|
74
|
+
Discussion of renaming existing classes / modules and JsonApi objects will
|
|
75
|
+
happen in separate pull requests, and issues, and in the google doc
|
|
76
|
+
https://docs.google.com/document/d/1rcrJr0sVcazY2Opd_6Kmv1iIwuHbI84s1P_NzFn-05c/edit?usp=sharing
|
|
77
|
+
|
|
78
|
+
Some of names already have a definition.
|
|
79
|
+
|
|
80
|
+
- Adapters get their own namespace under ActiveModelSerializers. E.g
|
|
81
|
+
`ActiveModelSerializers::Adapter`
|
|
82
|
+
- Serializers get their own namespace under ActiveModelSerializers. E.g
|
|
83
|
+
`ActiveModelSerializers::Serializer`
|
|
84
|
+
|
|
85
|
+
## Keeping compatibility
|
|
86
|
+
|
|
87
|
+
All moved classes or modules be aliased to their old name and location with
|
|
88
|
+
deprecation warnings, such as
|
|
89
|
+
[was done for CollectionSerializer](https://github.com/rails-api/active_model_serializers/pull/1251).
|
|
90
|
+
|
|
91
|
+
# Drawbacks
|
|
92
|
+
|
|
93
|
+
This will be a breaking change, so all users serializers will be broken after a
|
|
94
|
+
major bump.
|
|
95
|
+
All pull requests will need to rebase since the architeture will change a lot.
|
|
96
|
+
|
|
97
|
+
# Alternatives
|
|
98
|
+
|
|
99
|
+
We can keep the way it is, and keep in mind to not add another namespace as a
|
|
100
|
+
public API.
|
|
101
|
+
|
|
102
|
+
# Unresolved questions
|
|
103
|
+
|
|
104
|
+
What is the better class name to be used to the class that will be inherited at
|
|
105
|
+
the creation of a serializer. This can be discussed in other RFC or directly via
|
|
106
|
+
pull request.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
- Start Date: (YYYY-MM-DD)
|
|
2
|
+
- RFC PR: https://github.com/rails-api/active_model_serializers/pull/dddd
|
|
3
|
+
- ActiveModelSerializers Issue: https://github.com/rails-api/active_model_serializers/issues/dddd
|
|
4
|
+
|
|
5
|
+
# Summary
|
|
6
|
+
|
|
7
|
+
# Motivation
|
|
8
|
+
|
|
9
|
+
# Detailed design
|
|
10
|
+
|
|
11
|
+
# Drawbacks
|
|
12
|
+
|
|
13
|
+
# Alternatives
|
|
14
|
+
|
|
15
|
+
# Unresolved questions
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
|
2
|
+
require 'active_model_serializers/serialization_context'
|
|
3
|
+
|
|
4
|
+
module ActionController
|
|
5
|
+
module Serialization
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
include ActionController::Renderers
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
def serialization_scope(scope)
|
|
12
|
+
self._serialization_scope = scope
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
included do
|
|
17
|
+
class_attribute :_serialization_scope
|
|
18
|
+
self._serialization_scope = :current_user
|
|
19
|
+
|
|
20
|
+
attr_writer :namespace_for_serializer
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def namespace_for_serializer
|
|
24
|
+
@namespace_for_serializer ||= self.class.parent unless self.class.parent == Object
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def serialization_scope
|
|
28
|
+
return unless _serialization_scope && respond_to?(_serialization_scope, true)
|
|
29
|
+
|
|
30
|
+
send(_serialization_scope)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def get_serializer(resource, options = {})
|
|
34
|
+
unless use_adapter?
|
|
35
|
+
warn 'ActionController::Serialization#use_adapter? has been removed. '\
|
|
36
|
+
"Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
|
|
37
|
+
options[:adapter] = false
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
options.fetch(:namespace) { options[:namespace] = namespace_for_serializer }
|
|
41
|
+
|
|
42
|
+
serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)
|
|
43
|
+
serializable_resource.serialization_scope ||= options.fetch(:scope) { serialization_scope }
|
|
44
|
+
serializable_resource.serialization_scope_name = options.fetch(:scope_name) { _serialization_scope }
|
|
45
|
+
# For compatibility with the JSON renderer: `json.to_json(options) if json.is_a?(String)`.
|
|
46
|
+
# Otherwise, since `serializable_resource` is not a string, the renderer would call
|
|
47
|
+
# `to_json` on a String and given odd results, such as `"".to_json #=> '""'`
|
|
48
|
+
serializable_resource.adapter.is_a?(String) ? serializable_resource.adapter : serializable_resource
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Deprecated
|
|
52
|
+
def use_adapter?
|
|
53
|
+
true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
[:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
|
|
57
|
+
define_method renderer_method do |resource, options|
|
|
58
|
+
options.fetch(:serialization_context) do
|
|
59
|
+
options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request, options)
|
|
60
|
+
end
|
|
61
|
+
serializable_resource = get_serializer(resource, options)
|
|
62
|
+
super(serializable_resource, options)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,231 @@
|
|
|
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/associations'
|
|
8
|
+
require 'active_model/serializer/concerns/attributes'
|
|
9
|
+
require 'active_model/serializer/concerns/caching'
|
|
10
|
+
require 'active_model/serializer/concerns/configuration'
|
|
11
|
+
require 'active_model/serializer/concerns/links'
|
|
12
|
+
require 'active_model/serializer/concerns/meta'
|
|
13
|
+
require 'active_model/serializer/concerns/type'
|
|
14
|
+
require 'active_model/serializer/fieldset'
|
|
15
|
+
require 'active_model/serializer/lint'
|
|
16
|
+
|
|
17
|
+
# ActiveModel::Serializer is an abstract class that is
|
|
18
|
+
# reified when subclassed to decorate a resource.
|
|
19
|
+
module ActiveModel
|
|
20
|
+
class Serializer
|
|
21
|
+
# @see #serializable_hash for more details on these valid keys.
|
|
22
|
+
SERIALIZABLE_HASH_VALID_KEYS = [:only, :except, :methods, :include, :root].freeze
|
|
23
|
+
extend ActiveSupport::Autoload
|
|
24
|
+
autoload :Adapter
|
|
25
|
+
autoload :Null
|
|
26
|
+
include Configuration
|
|
27
|
+
include Associations
|
|
28
|
+
include Attributes
|
|
29
|
+
include Caching
|
|
30
|
+
include Links
|
|
31
|
+
include Meta
|
|
32
|
+
include Type
|
|
33
|
+
|
|
34
|
+
# @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
|
|
35
|
+
# @return [ActiveModel::Serializer]
|
|
36
|
+
# Preferentially returns
|
|
37
|
+
# 1. resource.serializer
|
|
38
|
+
# 2. ArraySerializer when resource is a collection
|
|
39
|
+
# 3. options[:serializer]
|
|
40
|
+
# 4. lookup serializer when resource is a Class
|
|
41
|
+
def self.serializer_for(resource, options = {})
|
|
42
|
+
if resource.respond_to?(:serializer_class)
|
|
43
|
+
resource.serializer_class
|
|
44
|
+
elsif resource.respond_to?(:to_ary)
|
|
45
|
+
config.collection_serializer
|
|
46
|
+
else
|
|
47
|
+
options.fetch(:serializer) { get_serializer_for(resource.class, options[:namespace]) }
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @see ActiveModelSerializers::Adapter.lookup
|
|
52
|
+
# Deprecated
|
|
53
|
+
def self.adapter
|
|
54
|
+
ActiveModelSerializers::Adapter.lookup(config.adapter)
|
|
55
|
+
end
|
|
56
|
+
class << self
|
|
57
|
+
extend ActiveModelSerializers::Deprecate
|
|
58
|
+
deprecate :adapter, 'ActiveModelSerializers::Adapter.configured_adapter'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @api private
|
|
62
|
+
def self.serializer_lookup_chain_for(klass, namespace = nil)
|
|
63
|
+
lookups = ActiveModelSerializers.config.serializer_lookup_chain
|
|
64
|
+
Array[*lookups].flat_map do |lookup|
|
|
65
|
+
lookup.call(klass, self, namespace)
|
|
66
|
+
end.compact
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Used to cache serializer name => serializer class
|
|
70
|
+
# when looked up by Serializer.get_serializer_for.
|
|
71
|
+
def self.serializers_cache
|
|
72
|
+
@serializers_cache ||= ThreadSafe::Cache.new
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @api private
|
|
76
|
+
# Find a serializer from a class and caches the lookup.
|
|
77
|
+
# Preferentially returns:
|
|
78
|
+
# 1. class name appended with "Serializer"
|
|
79
|
+
# 2. try again with superclass, if present
|
|
80
|
+
# 3. nil
|
|
81
|
+
def self.get_serializer_for(klass, namespace = nil)
|
|
82
|
+
return nil unless config.serializer_lookup_enabled
|
|
83
|
+
|
|
84
|
+
cache_key = ActiveSupport::Cache.expand_cache_key(klass, namespace)
|
|
85
|
+
serializers_cache.fetch_or_store(cache_key) do
|
|
86
|
+
# NOTE(beauby): When we drop 1.9.3 support we can lazify the map for perfs.
|
|
87
|
+
lookup_chain = serializer_lookup_chain_for(klass, namespace)
|
|
88
|
+
serializer_class = lookup_chain.map(&:safe_constantize).find { |x| x && x < ActiveModel::Serializer }
|
|
89
|
+
|
|
90
|
+
if serializer_class
|
|
91
|
+
serializer_class
|
|
92
|
+
elsif klass.superclass
|
|
93
|
+
get_serializer_for(klass.superclass)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @api private
|
|
99
|
+
def self.include_directive_from_options(options)
|
|
100
|
+
if options[:include_directive]
|
|
101
|
+
options[:include_directive]
|
|
102
|
+
elsif options[:include]
|
|
103
|
+
JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
|
|
104
|
+
else
|
|
105
|
+
ActiveModelSerializers.default_include_directive
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @api private
|
|
110
|
+
def self.serialization_adapter_instance
|
|
111
|
+
@serialization_adapter_instance ||= ActiveModelSerializers::Adapter::Attributes
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
attr_accessor :object, :root, :scope
|
|
115
|
+
|
|
116
|
+
# `scope_name` is set as :current_user by default in the controller.
|
|
117
|
+
# If the instance does not have a method named `scope_name`, it
|
|
118
|
+
# defines the method so that it calls the +scope+.
|
|
119
|
+
def initialize(object, options = {})
|
|
120
|
+
self.object = object
|
|
121
|
+
self.instance_options = options
|
|
122
|
+
self.root = instance_options[:root]
|
|
123
|
+
self.scope = instance_options[:scope]
|
|
124
|
+
|
|
125
|
+
return if !(scope_name = instance_options[:scope_name]) || respond_to?(scope_name)
|
|
126
|
+
|
|
127
|
+
define_singleton_method scope_name, -> { scope }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def success?
|
|
131
|
+
true
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# @return [Hash] containing the attributes and first level
|
|
135
|
+
# associations, similar to how ActiveModel::Serializers::JSON is used
|
|
136
|
+
# in ActiveRecord::Base.
|
|
137
|
+
#
|
|
138
|
+
# TODO: Include <tt>ActiveModel::Serializers::JSON</tt>.
|
|
139
|
+
# So that the below is true:
|
|
140
|
+
# @param options [nil, Hash] The same valid options passed to `serializable_hash`
|
|
141
|
+
# (:only, :except, :methods, and :include).
|
|
142
|
+
#
|
|
143
|
+
# See
|
|
144
|
+
# https://github.com/rails/rails/blob/v5.0.0.beta2/activemodel/lib/active_model/serializers/json.rb#L17-L101
|
|
145
|
+
# https://github.com/rails/rails/blob/v5.0.0.beta2/activemodel/lib/active_model/serialization.rb#L85-L123
|
|
146
|
+
# https://github.com/rails/rails/blob/v5.0.0.beta2/activerecord/lib/active_record/serialization.rb#L11-L17
|
|
147
|
+
# https://github.com/rails/rails/blob/v5.0.0.beta2/activesupport/lib/active_support/core_ext/object/json.rb#L147-L162
|
|
148
|
+
#
|
|
149
|
+
# @example
|
|
150
|
+
# # The :only and :except options can be used to limit the attributes included, and work
|
|
151
|
+
# # similar to the attributes method.
|
|
152
|
+
# serializer.as_json(only: [:id, :name])
|
|
153
|
+
# serializer.as_json(except: [:id, :created_at, :age])
|
|
154
|
+
#
|
|
155
|
+
# # To include the result of some method calls on the model use :methods:
|
|
156
|
+
# serializer.as_json(methods: :permalink)
|
|
157
|
+
#
|
|
158
|
+
# # To include associations use :include:
|
|
159
|
+
# serializer.as_json(include: :posts)
|
|
160
|
+
# # Second level and higher order associations work as well:
|
|
161
|
+
# serializer.as_json(include: { posts: { include: { comments: { only: :body } }, only: :title } })
|
|
162
|
+
def serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance)
|
|
163
|
+
adapter_options ||= {}
|
|
164
|
+
options[:include_directive] ||= ActiveModel::Serializer.include_directive_from_options(adapter_options)
|
|
165
|
+
cached_attributes = adapter_options[:cached_attributes] ||= {}
|
|
166
|
+
resource = fetch_attributes(options[:fields], cached_attributes, adapter_instance)
|
|
167
|
+
relationships = resource_relationships(adapter_options, options, adapter_instance)
|
|
168
|
+
resource.merge(relationships)
|
|
169
|
+
end
|
|
170
|
+
alias to_hash serializable_hash
|
|
171
|
+
alias to_h serializable_hash
|
|
172
|
+
|
|
173
|
+
# @see #serializable_hash
|
|
174
|
+
# TODO: When moving attributes adapter logic here, @see #serializable_hash
|
|
175
|
+
# So that the below is true:
|
|
176
|
+
# @param options [nil, Hash] The same valid options passed to `as_json`
|
|
177
|
+
# (:root, :only, :except, :methods, and :include).
|
|
178
|
+
# The default for `root` is nil.
|
|
179
|
+
# The default value for include_root is false. You can change it to true if the given
|
|
180
|
+
# JSON string includes a single root node.
|
|
181
|
+
def as_json(adapter_opts = nil)
|
|
182
|
+
serializable_hash(adapter_opts)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Used by adapter as resource root.
|
|
186
|
+
def json_key
|
|
187
|
+
root || _type || object.class.model_name.to_s.underscore
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def read_attribute_for_serialization(attr)
|
|
191
|
+
if respond_to?(attr)
|
|
192
|
+
send(attr)
|
|
193
|
+
else
|
|
194
|
+
object.read_attribute_for_serialization(attr)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# @api private
|
|
199
|
+
def resource_relationships(adapter_options, options, adapter_instance)
|
|
200
|
+
relationships = {}
|
|
201
|
+
include_directive = options.fetch(:include_directive)
|
|
202
|
+
associations(include_directive).each do |association|
|
|
203
|
+
adapter_opts = adapter_options.merge(include_directive: include_directive[association.key])
|
|
204
|
+
relationships[association.key] ||= relationship_value_for(association, adapter_opts, adapter_instance)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
relationships
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# @api private
|
|
211
|
+
def relationship_value_for(association, adapter_options, adapter_instance)
|
|
212
|
+
return association.options[:virtual_value] if association.options[:virtual_value]
|
|
213
|
+
association_serializer = association.serializer
|
|
214
|
+
association_object = association_serializer && association_serializer.object
|
|
215
|
+
return unless association_object
|
|
216
|
+
|
|
217
|
+
relationship_value = association_serializer.serializable_hash(adapter_options, {}, adapter_instance)
|
|
218
|
+
|
|
219
|
+
if association.options[:polymorphic] && relationship_value
|
|
220
|
+
polymorphic_type = association_object.class.name.underscore
|
|
221
|
+
relationship_value = { type: polymorphic_type, polymorphic_type.to_sym => relationship_value }
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
relationship_value
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
protected
|
|
228
|
+
|
|
229
|
+
attr_accessor :instance_options
|
|
230
|
+
end
|
|
231
|
+
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'
|