active_model_serializers 0.10.0 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -4
  3. data/.travis.yml +17 -5
  4. data/CHANGELOG.md +112 -2
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +5 -2
  7. data/README.md +166 -26
  8. data/Rakefile +3 -3
  9. data/active_model_serializers.gemspec +21 -24
  10. data/appveyor.yml +9 -3
  11. data/docs/README.md +2 -1
  12. data/docs/general/adapters.md +4 -2
  13. data/docs/general/caching.md +7 -1
  14. data/docs/general/configuration_options.md +70 -1
  15. data/docs/general/deserialization.md +1 -1
  16. data/docs/general/fields.md +31 -0
  17. data/docs/general/logging.md +7 -0
  18. data/docs/general/rendering.md +44 -20
  19. data/docs/general/serializers.md +100 -11
  20. data/docs/howto/add_pagination_links.md +15 -16
  21. data/docs/howto/add_relationship_links.md +140 -0
  22. data/docs/howto/add_root_key.md +4 -0
  23. data/docs/howto/grape_integration.md +42 -0
  24. data/docs/howto/outside_controller_use.md +12 -4
  25. data/docs/howto/passing_arbitrary_options.md +2 -2
  26. data/docs/howto/serialize_poro.md +46 -5
  27. data/docs/howto/test.md +2 -0
  28. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  29. data/docs/integrations/ember-and-json-api.md +64 -32
  30. data/docs/jsonapi/schema.md +1 -1
  31. data/lib/action_controller/serialization.rb +13 -3
  32. data/lib/active_model/serializer/adapter/base.rb +2 -0
  33. data/lib/active_model/serializer/array_serializer.rb +8 -5
  34. data/lib/active_model/serializer/association.rb +19 -4
  35. data/lib/active_model/serializer/belongs_to_reflection.rb +0 -3
  36. data/lib/active_model/serializer/collection_serializer.rb +35 -12
  37. data/lib/active_model/serializer/{associations.rb → concerns/associations.rb} +13 -11
  38. data/lib/active_model/serializer/{attributes.rb → concerns/attributes.rb} +1 -1
  39. data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +72 -113
  40. data/lib/active_model/serializer/{configuration.rb → concerns/configuration.rb} +25 -1
  41. data/lib/active_model/serializer/{links.rb → concerns/links.rb} +0 -0
  42. data/lib/active_model/serializer/{meta.rb → concerns/meta.rb} +0 -0
  43. data/lib/active_model/serializer/{type.rb → concerns/type.rb} +0 -0
  44. data/lib/active_model/serializer/error_serializer.rb +11 -7
  45. data/lib/active_model/serializer/errors_serializer.rb +25 -20
  46. data/lib/active_model/serializer/has_many_reflection.rb +0 -3
  47. data/lib/active_model/serializer/has_one_reflection.rb +0 -3
  48. data/lib/active_model/serializer/lint.rb +134 -130
  49. data/lib/active_model/serializer/reflection.rb +37 -21
  50. data/lib/active_model/serializer/version.rb +1 -1
  51. data/lib/active_model/serializer.rb +76 -37
  52. data/lib/active_model_serializers/adapter/attributes.rb +3 -66
  53. data/lib/active_model_serializers/adapter/base.rb +39 -39
  54. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +1 -1
  55. data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
  56. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +8 -1
  57. data/lib/active_model_serializers/adapter/json_api/relationship.rb +30 -19
  58. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +23 -9
  59. data/lib/active_model_serializers/adapter/json_api.rb +44 -43
  60. data/lib/active_model_serializers/adapter.rb +6 -0
  61. data/lib/active_model_serializers/deprecate.rb +1 -2
  62. data/lib/active_model_serializers/deserialization.rb +2 -0
  63. data/lib/active_model_serializers/lookup_chain.rb +80 -0
  64. data/lib/active_model_serializers/model.rb +108 -28
  65. data/lib/active_model_serializers/railtie.rb +3 -1
  66. data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
  67. data/lib/active_model_serializers/serializable_resource.rb +6 -5
  68. data/lib/active_model_serializers/serialization_context.rb +10 -3
  69. data/lib/active_model_serializers/test/schema.rb +2 -2
  70. data/lib/active_model_serializers.rb +15 -0
  71. data/lib/generators/rails/resource_override.rb +1 -1
  72. data/lib/generators/rails/serializer_generator.rb +4 -4
  73. data/lib/grape/active_model_serializers.rb +7 -5
  74. data/lib/grape/formatters/active_model_serializers.rb +19 -2
  75. data/lib/grape/helpers/active_model_serializers.rb +1 -0
  76. data/test/action_controller/adapter_selector_test.rb +14 -5
  77. data/test/action_controller/explicit_serializer_test.rb +5 -4
  78. data/test/action_controller/json/include_test.rb +106 -27
  79. data/test/action_controller/json_api/errors_test.rb +8 -9
  80. data/test/action_controller/json_api/fields_test.rb +66 -0
  81. data/test/action_controller/json_api/linked_test.rb +29 -24
  82. data/test/action_controller/json_api/pagination_test.rb +19 -19
  83. data/test/action_controller/json_api/transform_test.rb +11 -3
  84. data/test/action_controller/lookup_proc_test.rb +49 -0
  85. data/test/action_controller/namespace_lookup_test.rb +232 -0
  86. data/test/action_controller/serialization_scope_name_test.rb +12 -6
  87. data/test/action_controller/serialization_test.rb +12 -9
  88. data/test/active_model_serializers/json_pointer_test.rb +15 -13
  89. data/test/active_model_serializers/model_test.rb +137 -4
  90. data/test/active_model_serializers/railtie_test_isolated.rb +12 -7
  91. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
  92. data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
  93. data/test/active_model_serializers/test/schema_test.rb +3 -2
  94. data/test/adapter/attributes_test.rb +40 -0
  95. data/test/adapter/json/collection_test.rb +14 -0
  96. data/test/adapter/json/has_many_test.rb +10 -2
  97. data/test/adapter/json/transform_test.rb +15 -15
  98. data/test/adapter/json_api/collection_test.rb +4 -3
  99. data/test/adapter/json_api/errors_test.rb +17 -19
  100. data/test/adapter/json_api/fields_test.rb +12 -3
  101. data/test/adapter/json_api/has_many_test.rb +49 -20
  102. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +183 -0
  103. data/test/adapter/json_api/json_api_test.rb +5 -7
  104. data/test/adapter/json_api/linked_test.rb +33 -12
  105. data/test/adapter/json_api/links_test.rb +4 -2
  106. data/test/adapter/json_api/pagination_links_test.rb +35 -8
  107. data/test/adapter/json_api/relationship_test.rb +309 -73
  108. data/test/adapter/json_api/resource_identifier_test.rb +27 -2
  109. data/test/adapter/json_api/resource_meta_test.rb +3 -3
  110. data/test/adapter/json_api/transform_test.rb +263 -253
  111. data/test/adapter/json_api/type_test.rb +1 -1
  112. data/test/adapter/json_test.rb +8 -7
  113. data/test/adapter/null_test.rb +1 -2
  114. data/test/adapter/polymorphic_test.rb +5 -5
  115. data/test/adapter_test.rb +1 -1
  116. data/test/benchmark/app.rb +1 -1
  117. data/test/benchmark/benchmarking_support.rb +1 -1
  118. data/test/benchmark/bm_active_record.rb +81 -0
  119. data/test/benchmark/bm_adapter.rb +38 -0
  120. data/test/benchmark/bm_caching.rb +16 -16
  121. data/test/benchmark/bm_lookup_chain.rb +83 -0
  122. data/test/benchmark/bm_transform.rb +21 -10
  123. data/test/benchmark/controllers.rb +16 -17
  124. data/test/benchmark/fixtures.rb +72 -72
  125. data/test/cache_test.rb +235 -69
  126. data/test/collection_serializer_test.rb +25 -12
  127. data/test/fixtures/active_record.rb +45 -10
  128. data/test/fixtures/poro.rb +124 -181
  129. data/test/generators/serializer_generator_test.rb +23 -5
  130. data/test/grape_test.rb +170 -56
  131. data/test/lint_test.rb +1 -1
  132. data/test/logger_test.rb +13 -11
  133. data/test/serializable_resource_test.rb +18 -22
  134. data/test/serializers/association_macros_test.rb +3 -2
  135. data/test/serializers/associations_test.rb +132 -36
  136. data/test/serializers/attribute_test.rb +5 -3
  137. data/test/serializers/attributes_test.rb +1 -1
  138. data/test/serializers/caching_configuration_test_isolated.rb +6 -6
  139. data/test/serializers/fieldset_test.rb +1 -1
  140. data/test/serializers/meta_test.rb +12 -6
  141. data/test/serializers/options_test.rb +17 -6
  142. data/test/serializers/read_attribute_for_serialization_test.rb +3 -3
  143. data/test/serializers/root_test.rb +1 -1
  144. data/test/serializers/serialization_test.rb +2 -2
  145. data/test/serializers/serializer_for_test.rb +12 -10
  146. data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
  147. data/test/support/isolated_unit.rb +5 -2
  148. data/test/support/rails5_shims.rb +8 -2
  149. data/test/support/rails_app.rb +2 -9
  150. data/test/support/serialization_testing.rb +23 -5
  151. data/test/test_helper.rb +13 -0
  152. metadata +104 -38
  153. data/.rubocop_todo.yml +0 -167
  154. data/docs/ARCHITECTURE.md +0 -126
  155. data/lib/active_model/serializer/include_tree.rb +0 -111
  156. data/lib/active_model_serializers/key_transform.rb +0 -70
  157. data/test/active_model_serializers/key_transform_test.rb +0 -263
  158. data/test/adapter/json_api/relationships_test.rb +0 -199
  159. data/test/include_tree/from_include_args_test.rb +0 -26
  160. data/test/include_tree/from_string_test.rb +0 -94
  161. data/test/include_tree/include_args_to_hash_test.rb +0 -64
@@ -17,25 +17,72 @@ To solve this, in Ember, both the adapter and the serializer will need some modi
17
17
 
18
18
  ### Server-Side Changes
19
19
 
20
- there are multiple mimetypes for json that should all be parsed similarly, so
21
- in `config/initializers/mime_types.rb`:
20
+ First, set the adapter type in an initializer file:
21
+
22
+ ```ruby
23
+ # config/initializers/active_model_serializers.rb
24
+ ActiveModelSerializers.config.adapter = :json_api
25
+ ```
26
+
27
+ or:
28
+
29
+ ```ruby
30
+ # config/initializers/active_model_serializers.rb
31
+ ActiveModelSerializers.config.adapter = ActiveModelSerializers::Adapter::JsonApi
32
+ ```
33
+
34
+ You will also want to set the `key_transform` to `:unaltered` since you will adjust the attributes in your Ember serializer to use underscores instead of dashes later. You could also use `:underscore`, but `:unaltered` is better for performance.
35
+
22
36
  ```ruby
23
- api_mime_types = %W(
24
- application/vnd.api+json
25
- text/x-json
26
- application/json
27
- )
28
-
29
- Mime::Type.unregister :json
30
- Mime::Type.register 'application/json', :json, api_mime_types
37
+ # config/initializers/active_model_serializers.rb
38
+ ActiveModelSerializers.config.key_transform = :unaltered
31
39
  ```
32
40
 
41
+ In order to properly handle JSON API responses, we need to register a JSON API renderer, like so:
42
+
43
+ ```ruby
44
+ # config/initializers/active_model_serializers.rb
45
+ ActiveSupport.on_load(:action_controller) do
46
+ require 'active_model_serializers/register_jsonapi_renderer'
47
+ end
48
+ ```
49
+ Rails also requires your controller to tell it that you accept and generate JSONAPI data. To do that, you use `respond_to` in your controller handlers to tell rails you are consuming and returning jsonapi format data. Without this, Rails will refuse to parse the request body into params. You can add `ActionController::MimeResponds` to your application controller to enable this:
50
+
51
+ ```ruby
52
+ class ApplicationController < ActionController::API
53
+ include ActionController::MimeResponds
54
+ end
55
+ ```
56
+ Then, in your controller you can tell rails you're accepting and rendering the jsonapi format:
57
+ ```ruby
58
+ # POST /post
59
+ def create
60
+ @post = Post.new(post_params)
61
+ respond_to do |format|
62
+ if @post.save
63
+ format.jsonapi { render jsonapi: @post, status: :created, location: @post }
64
+ else
65
+ format.jsonapi { render jsonapi: @post.errors, status: :unprocessable_entity }
66
+ end
67
+ end
68
+ end
69
+
70
+ # Only allow a trusted parameter "white list" through.
71
+ def post_params
72
+ ActiveModelSerializers::Deserialization.jsonapi_parse!(params, only: [:title, :body] )
73
+ end
74
+ end
75
+ ```
76
+
77
+
33
78
  ### Adapter Changes
34
79
 
35
80
  ```javascript
36
81
  // app/adapters/application.js
82
+ import Ember from 'ember';
37
83
  import DS from 'ember-data';
38
84
  import ENV from "../config/environment";
85
+ const { underscore, pluralize } = Ember.String;
39
86
 
40
87
  export default DS.JSONAPIAdapter.extend({
41
88
  namespace: 'api',
@@ -46,22 +93,10 @@ export default DS.JSONAPIAdapter.extend({
46
93
 
47
94
  // allows the multiword paths in urls to be underscored
48
95
  pathForType: function(type) {
49
- let underscored = Ember.String.underscore(type);
50
- return Ember.String.pluralize(underscored);
96
+ let underscored = underscore(type);
97
+ return pluralize(underscored);
51
98
  },
52
99
 
53
- // allows queries to be sent along with a findRecord
54
- // hopefully Ember / EmberData will soon have this built in
55
- // ember-data issue tracked here:
56
- // https://github.com/emberjs/data/issues/3596
57
- urlForFindRecord(id, modelName, snapshot) {
58
- let url = this._super(...arguments);
59
- let query = Ember.get(snapshot, 'adapterOptions.query');
60
- if(query) {
61
- url += '?' + Ember.$.param(query);
62
- }
63
- return url;
64
- }
65
100
  });
66
101
  ```
67
102
 
@@ -85,22 +120,19 @@ export default DS.JSONAPISerializer.extend({
85
120
 
86
121
  ```
87
122
 
88
- ## Including Nested Resources
89
123
 
90
- Previously, `store.find` and `store.findRecord` did not allow specification of any query params.
91
- The ActiveModelSerializers default for the `include` parameter is to be `nil` meaning that if any associations are defined in your serializer, only the `id` and `type` will be in the `relationships` structure of the JSON API response.
92
- For more on `include` usage, see: [The JSON API include examples](./../general/adapters.md#JSON-API)
124
+ ## Including Nested Resources
93
125
 
94
- With the above modifications, you can execute code as below in order to include nested resources while doing a find query.
126
+ Ember Data can request related records by using `include`. Below are some examples of how to make Ember Data request the inclusion of related records. For more on `include` usage, see: [The JSON API include examples](./../general/adapters.md#JSON-API)
95
127
 
96
128
  ```javascript
97
- store.findRecord('post', postId, { adapterOptions: { query: { include: 'comments' } } });
129
+ store.findRecord('post', postId, { include: 'comments' } );
98
130
  ```
99
- will generate the path `/posts/{postId}?include='comments'`
131
+ which will generate the path /posts/{postId}?include='comments'
100
132
 
101
133
  So then in your controller, you'll want to be sure to have something like:
102
134
  ```ruby
103
- render json: @post, include: params[:include]
135
+ render jsonapi: @post, include: params[:include]
104
136
  ```
105
137
 
106
138
  If you want to use `include` on a collection, you'd write something like this:
@@ -28,7 +28,7 @@ Example supported requests
28
28
  - Relationships
29
29
  - GET /articles/1/relationships/comments
30
30
  - GET /articles/1/relationships/author
31
- - Optional: [Inclusion of related resources](http://jsonapi.org/format/#fetching-includes) `ActiveModel::Serializer::IncludeTree`
31
+ - Optional: [Inclusion of related resources](http://jsonapi.org/format/#fetching-includes) `JSONAPI::IncludeDirective`
32
32
  - GET /articles/1?`include`=comments
33
33
  - GET /articles/1?`include`=comments.author
34
34
  - GET /articles/1?`include`=author,comments.author
@@ -16,19 +16,29 @@ module ActionController
16
16
  included do
17
17
  class_attribute :_serialization_scope
18
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
19
25
  end
20
26
 
21
27
  def serialization_scope
22
- send(_serialization_scope) if _serialization_scope &&
23
- respond_to?(_serialization_scope, true)
28
+ return unless _serialization_scope && respond_to?(_serialization_scope, true)
29
+
30
+ send(_serialization_scope)
24
31
  end
25
32
 
26
33
  def get_serializer(resource, options = {})
27
- if !use_adapter?
34
+ unless use_adapter?
28
35
  warn 'ActionController::Serialization#use_adapter? has been removed. '\
29
36
  "Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
30
37
  options[:adapter] = false
31
38
  end
39
+
40
+ options.fetch(:namespace) { options[:namespace] = namespace_for_serializer }
41
+
32
42
  serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)
33
43
  serializable_resource.serialization_scope ||= options.fetch(:scope) { serialization_scope }
34
44
  serializable_resource.serialization_scope_name = options.fetch(:scope_name) { _serialization_scope }
@@ -7,9 +7,11 @@ module ActiveModel
7
7
  deprecate :inherited, 'ActiveModelSerializers::Adapter::Base.'
8
8
  end
9
9
 
10
+ # :nocov:
10
11
  def initialize(serializer, options = {})
11
12
  super(ActiveModelSerializers::Adapter::Base.new(serializer, options))
12
13
  end
14
+ # :nocov:
13
15
  end
14
16
  end
15
17
  end
@@ -1,9 +1,12 @@
1
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.'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class ArraySerializer < CollectionSerializer
6
+ class << self
7
+ extend ActiveModelSerializers::Deprecate
8
+ deprecate :new, 'ActiveModel::Serializer::CollectionSerializer.'
9
+ end
7
10
  end
8
11
  end
9
12
  end
@@ -1,19 +1,34 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
- # This class hold all information about serializer's association.
3
+ # This class holds all information about serializer's association.
4
4
  #
5
5
  # @attr [Symbol] name
6
- # @attr [ActiveModel::Serializer] serializer
7
6
  # @attr [Hash{Symbol => Object}] options
7
+ # @attr [block]
8
8
  #
9
9
  # @example
10
- # Association.new(:comments, CommentSummarySerializer)
10
+ # Association.new(:comments, { serializer: CommentSummarySerializer })
11
11
  #
12
- Association = Struct.new(:name, :serializer, :options, :links, :meta) do
12
+ class Association < Field
13
13
  # @return [Symbol]
14
14
  def key
15
15
  options.fetch(:key, name)
16
16
  end
17
+
18
+ # @return [ActiveModel::Serializer, nil]
19
+ def serializer
20
+ options[:serializer]
21
+ end
22
+
23
+ # @return [Hash]
24
+ def links
25
+ options.fetch(:links) || {}
26
+ end
27
+
28
+ # @return [Hash, nil]
29
+ def meta
30
+ options[:meta]
31
+ end
17
32
  end
18
33
  end
19
34
  end
@@ -2,9 +2,6 @@ module ActiveModel
2
2
  class Serializer
3
3
  # @api private
4
4
  class BelongsToReflection < SingularReflection
5
- def macro
6
- :belongs_to
7
- end
8
5
  end
9
6
  end
10
7
  end
@@ -1,7 +1,6 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
3
  class CollectionSerializer
4
- NoSerializerError = Class.new(StandardError)
5
4
  include Enumerable
6
5
  delegate :each, to: :@serializers
7
6
 
@@ -11,22 +10,23 @@ module ActiveModel
11
10
  @object = resources
12
11
  @options = options
13
12
  @root = options[:root]
14
- serializer_context_class = options.fetch(:serializer_context_class, ActiveModel::Serializer)
15
- @serializers = resources.map do |resource|
16
- serializer_class = options.fetch(:serializer) { serializer_context_class.serializer_for(resource) }
17
-
18
- if serializer_class.nil? # rubocop:disable Style/GuardClause
19
- fail NoSerializerError, "No serializer found for resource: #{resource.inspect}"
20
- else
21
- serializer_class.new(resource, options.except(:serializer))
22
- end
23
- end
13
+ @serializers = serializers_from_resources
24
14
  end
25
15
 
26
16
  def success?
27
17
  true
28
18
  end
29
19
 
20
+ # @api private
21
+ def serializable_hash(adapter_options, options, adapter_instance)
22
+ include_directive = ActiveModel::Serializer.include_directive_from_options(adapter_options)
23
+ adapter_options[:cached_attributes] ||= ActiveModel::Serializer.cache_read_multi(self, adapter_instance, include_directive)
24
+ adapter_opts = adapter_options.merge(include_directive: include_directive)
25
+ serializers.map do |serializer|
26
+ serializer.serializable_hash(adapter_opts, options, adapter_instance)
27
+ end
28
+ end
29
+
30
30
  # TODO: unify naming of root, json_key, and _type. Right now, a serializer's
31
31
  # json_key comes from the root option or the object's model name, by default.
32
32
  # But, if a dev defines a custom `json_key` method with an explicit value,
@@ -51,7 +51,8 @@ module ActiveModel
51
51
  # rubocop:enable Metrics/CyclomaticComplexity
52
52
 
53
53
  def paginated?
54
- object.respond_to?(:current_page) &&
54
+ ActiveModelSerializers.config.jsonapi_pagination_links_enabled &&
55
+ object.respond_to?(:current_page) &&
55
56
  object.respond_to?(:total_pages) &&
56
57
  object.respond_to?(:size)
57
58
  end
@@ -59,6 +60,28 @@ module ActiveModel
59
60
  protected
60
61
 
61
62
  attr_reader :serializers, :options
63
+
64
+ private
65
+
66
+ def serializers_from_resources
67
+ serializer_context_class = options.fetch(:serializer_context_class, ActiveModel::Serializer)
68
+ object.map do |resource|
69
+ serializer_from_resource(resource, serializer_context_class, options)
70
+ end
71
+ end
72
+
73
+ def serializer_from_resource(resource, serializer_context_class, options)
74
+ serializer_class = options.fetch(:serializer) do
75
+ serializer_context_class.serializer_for(resource, namespace: options[:namespace])
76
+ end
77
+
78
+ if serializer_class.nil?
79
+ ActiveModelSerializers.logger.debug "No serializer found for resource: #{resource.inspect}"
80
+ throw :no_serializer
81
+ else
82
+ serializer_class.new(resource, options.except(:serializer))
83
+ end
84
+ end
62
85
  end
63
86
  end
64
87
  end
@@ -10,12 +10,10 @@ module ActiveModel
10
10
  module Associations
11
11
  extend ActiveSupport::Concern
12
12
 
13
- DEFAULT_INCLUDE_TREE = ActiveModel::Serializer::IncludeTree.from_string('*')
14
-
15
13
  included do
16
14
  with_options instance_writer: false, instance_reader: true do |serializer|
17
15
  serializer.class_attribute :_reflections
18
- self._reflections ||= []
16
+ self._reflections ||= {}
19
17
  end
20
18
 
21
19
  extend ActiveSupport::Autoload
@@ -41,7 +39,7 @@ module ActiveModel
41
39
  # @example
42
40
  # has_many :comments, serializer: CommentSummarySerializer
43
41
  #
44
- def has_many(name, options = {}, &block)
42
+ def has_many(name, options = {}, &block) # rubocop:disable Style/PredicateName
45
43
  associate(HasManyReflection.new(name, options, block))
46
44
  end
47
45
 
@@ -63,7 +61,7 @@ module ActiveModel
63
61
  # @example
64
62
  # has_one :author, serializer: AuthorSerializer
65
63
  #
66
- def has_one(name, options = {}, &block)
64
+ def has_one(name, options = {}, &block) # rubocop:disable Style/PredicateName
67
65
  associate(HasOneReflection.new(name, options, block))
68
66
  end
69
67
 
@@ -76,22 +74,26 @@ module ActiveModel
76
74
  # @api private
77
75
  #
78
76
  def associate(reflection)
79
- self._reflections << reflection
77
+ key = reflection.options[:key] || reflection.name
78
+ self._reflections[key] = reflection
80
79
  end
81
80
  end
82
81
 
83
- # @param [IncludeTree] include_tree (defaults to all associations when not provided)
82
+ # @param [JSONAPI::IncludeDirective] include_directive (defaults to the
83
+ # +default_include_directive+ config value when not provided)
84
84
  # @return [Enumerator<Association>]
85
85
  #
86
- def associations(include_tree = DEFAULT_INCLUDE_TREE)
86
+ def associations(include_directive = ActiveModelSerializers.default_include_directive, include_slice = nil)
87
+ include_slice ||= include_directive
87
88
  return unless object
88
89
 
89
90
  Enumerator.new do |y|
90
- self.class._reflections.each do |reflection|
91
+ self.class._reflections.values.each do |reflection|
91
92
  next if reflection.excluded?(self)
92
93
  key = reflection.options.fetch(:key, reflection.name)
93
- next unless include_tree.key?(key)
94
- y.yield reflection.build_association(self, instance_options)
94
+ next unless include_directive.key?(key)
95
+
96
+ y.yield reflection.build_association(self, instance_options, include_slice)
95
97
  end
96
98
  end
97
99
  end
@@ -66,7 +66,7 @@ module ActiveModel
66
66
  end
67
67
 
68
68
  # @api private
69
- # maps attribute value to explict key name
69
+ # maps attribute value to explicit key name
70
70
  # @see Serializer::attribute
71
71
  # @see FragmentCache#fragment_serializer
72
72
  def _attributes_keys