active_model_serializers 0.10.0 → 0.10.13

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.
Files changed (215) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +239 -2
  3. data/README.md +171 -34
  4. data/lib/action_controller/serialization.rb +23 -3
  5. data/lib/active_model/serializable_resource.rb +2 -0
  6. data/lib/active_model/serializer/adapter/attributes.rb +2 -0
  7. data/lib/active_model/serializer/adapter/base.rb +4 -0
  8. data/lib/active_model/serializer/adapter/json.rb +2 -0
  9. data/lib/active_model/serializer/adapter/json_api.rb +2 -0
  10. data/lib/active_model/serializer/adapter/null.rb +2 -0
  11. data/lib/active_model/serializer/adapter.rb +2 -0
  12. data/lib/active_model/serializer/array_serializer.rb +10 -5
  13. data/lib/active_model/serializer/association.rb +64 -10
  14. data/lib/active_model/serializer/attribute.rb +2 -0
  15. data/lib/active_model/serializer/belongs_to_reflection.rb +6 -3
  16. data/lib/active_model/serializer/collection_serializer.rb +48 -13
  17. data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +89 -117
  18. data/lib/active_model/serializer/error_serializer.rb +13 -7
  19. data/lib/active_model/serializer/errors_serializer.rb +27 -20
  20. data/lib/active_model/serializer/field.rb +2 -0
  21. data/lib/active_model/serializer/fieldset.rb +3 -1
  22. data/lib/active_model/serializer/has_many_reflection.rb +5 -3
  23. data/lib/active_model/serializer/has_one_reflection.rb +3 -4
  24. data/lib/active_model/serializer/lazy_association.rb +99 -0
  25. data/lib/active_model/serializer/link.rb +23 -0
  26. data/lib/active_model/serializer/lint.rb +136 -130
  27. data/lib/active_model/serializer/null.rb +2 -0
  28. data/lib/active_model/serializer/reflection.rb +130 -65
  29. data/lib/active_model/serializer/version.rb +3 -1
  30. data/lib/active_model/serializer.rb +321 -86
  31. data/lib/active_model_serializers/adapter/attributes.rb +17 -57
  32. data/lib/active_model_serializers/adapter/base.rb +41 -39
  33. data/lib/active_model_serializers/adapter/json.rb +2 -0
  34. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +4 -2
  35. data/lib/active_model_serializers/adapter/json_api/error.rb +2 -0
  36. data/lib/active_model_serializers/adapter/json_api/jsonapi.rb +2 -0
  37. data/lib/active_model_serializers/adapter/json_api/link.rb +3 -1
  38. data/lib/active_model_serializers/adapter/json_api/meta.rb +2 -0
  39. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +52 -20
  40. data/lib/active_model_serializers/adapter/json_api/relationship.rb +77 -23
  41. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +41 -10
  42. data/lib/active_model_serializers/adapter/json_api.rb +84 -65
  43. data/lib/active_model_serializers/adapter/null.rb +2 -0
  44. data/lib/active_model_serializers/adapter.rb +9 -1
  45. data/lib/active_model_serializers/callbacks.rb +2 -0
  46. data/lib/active_model_serializers/deprecate.rb +3 -2
  47. data/lib/active_model_serializers/deserialization.rb +4 -0
  48. data/lib/active_model_serializers/json_pointer.rb +2 -0
  49. data/lib/active_model_serializers/logging.rb +2 -0
  50. data/lib/active_model_serializers/lookup_chain.rb +82 -0
  51. data/lib/active_model_serializers/model/caching.rb +26 -0
  52. data/lib/active_model_serializers/model.rb +111 -28
  53. data/lib/active_model_serializers/railtie.rb +7 -1
  54. data/lib/active_model_serializers/register_jsonapi_renderer.rb +46 -31
  55. data/lib/active_model_serializers/serializable_resource.rb +10 -7
  56. data/lib/active_model_serializers/serialization_context.rb +12 -3
  57. data/lib/active_model_serializers/test/schema.rb +4 -2
  58. data/lib/active_model_serializers/test/serializer.rb +2 -0
  59. data/lib/active_model_serializers/test.rb +2 -0
  60. data/lib/active_model_serializers.rb +35 -10
  61. data/lib/generators/rails/resource_override.rb +3 -1
  62. data/lib/generators/rails/serializer_generator.rb +6 -4
  63. data/lib/grape/active_model_serializers.rb +9 -5
  64. data/lib/grape/formatters/active_model_serializers.rb +21 -2
  65. data/lib/grape/helpers/active_model_serializers.rb +3 -0
  66. data/lib/tasks/rubocop.rake +55 -0
  67. metadata +104 -296
  68. data/.github/ISSUE_TEMPLATE.md +0 -29
  69. data/.github/PULL_REQUEST_TEMPLATE.md +0 -15
  70. data/.gitignore +0 -35
  71. data/.rubocop.yml +0 -104
  72. data/.rubocop_todo.yml +0 -167
  73. data/.simplecov +0 -110
  74. data/.travis.yml +0 -43
  75. data/CONTRIBUTING.md +0 -105
  76. data/Gemfile +0 -53
  77. data/Rakefile +0 -103
  78. data/active_model_serializers.gemspec +0 -66
  79. data/appveyor.yml +0 -24
  80. data/bin/bench +0 -171
  81. data/bin/bench_regression +0 -316
  82. data/bin/serve_benchmark +0 -39
  83. data/docs/ARCHITECTURE.md +0 -126
  84. data/docs/README.md +0 -40
  85. data/docs/STYLE.md +0 -58
  86. data/docs/general/adapters.md +0 -245
  87. data/docs/general/caching.md +0 -52
  88. data/docs/general/configuration_options.md +0 -100
  89. data/docs/general/deserialization.md +0 -100
  90. data/docs/general/getting_started.md +0 -133
  91. data/docs/general/instrumentation.md +0 -40
  92. data/docs/general/key_transforms.md +0 -40
  93. data/docs/general/logging.md +0 -14
  94. data/docs/general/rendering.md +0 -255
  95. data/docs/general/serializers.md +0 -372
  96. data/docs/how-open-source-maintained.jpg +0 -0
  97. data/docs/howto/add_pagination_links.md +0 -139
  98. data/docs/howto/add_root_key.md +0 -51
  99. data/docs/howto/outside_controller_use.md +0 -58
  100. data/docs/howto/passing_arbitrary_options.md +0 -27
  101. data/docs/howto/serialize_poro.md +0 -32
  102. data/docs/howto/test.md +0 -152
  103. data/docs/integrations/ember-and-json-api.md +0 -112
  104. data/docs/integrations/grape.md +0 -19
  105. data/docs/jsonapi/errors.md +0 -56
  106. data/docs/jsonapi/schema/schema.json +0 -366
  107. data/docs/jsonapi/schema.md +0 -151
  108. data/docs/rfcs/0000-namespace.md +0 -106
  109. data/docs/rfcs/template.md +0 -15
  110. data/lib/active_model/serializer/associations.rb +0 -100
  111. data/lib/active_model/serializer/attributes.rb +0 -82
  112. data/lib/active_model/serializer/collection_reflection.rb +0 -7
  113. data/lib/active_model/serializer/configuration.rb +0 -35
  114. data/lib/active_model/serializer/include_tree.rb +0 -111
  115. data/lib/active_model/serializer/links.rb +0 -35
  116. data/lib/active_model/serializer/meta.rb +0 -29
  117. data/lib/active_model/serializer/singular_reflection.rb +0 -7
  118. data/lib/active_model/serializer/type.rb +0 -25
  119. data/lib/active_model_serializers/key_transform.rb +0 -70
  120. data/test/action_controller/adapter_selector_test.rb +0 -53
  121. data/test/action_controller/explicit_serializer_test.rb +0 -134
  122. data/test/action_controller/json/include_test.rb +0 -167
  123. data/test/action_controller/json_api/deserialization_test.rb +0 -112
  124. data/test/action_controller/json_api/errors_test.rb +0 -41
  125. data/test/action_controller/json_api/linked_test.rb +0 -197
  126. data/test/action_controller/json_api/pagination_test.rb +0 -116
  127. data/test/action_controller/json_api/transform_test.rb +0 -181
  128. data/test/action_controller/serialization_scope_name_test.rb +0 -229
  129. data/test/action_controller/serialization_test.rb +0 -469
  130. data/test/active_model_serializers/adapter_for_test.rb +0 -208
  131. data/test/active_model_serializers/json_pointer_test.rb +0 -20
  132. data/test/active_model_serializers/key_transform_test.rb +0 -263
  133. data/test/active_model_serializers/logging_test.rb +0 -77
  134. data/test/active_model_serializers/model_test.rb +0 -9
  135. data/test/active_model_serializers/railtie_test_isolated.rb +0 -63
  136. data/test/active_model_serializers/serialization_context_test_isolated.rb +0 -58
  137. data/test/active_model_serializers/test/schema_test.rb +0 -130
  138. data/test/active_model_serializers/test/serializer_test.rb +0 -62
  139. data/test/active_record_test.rb +0 -9
  140. data/test/adapter/deprecation_test.rb +0 -100
  141. data/test/adapter/json/belongs_to_test.rb +0 -45
  142. data/test/adapter/json/collection_test.rb +0 -90
  143. data/test/adapter/json/has_many_test.rb +0 -45
  144. data/test/adapter/json/transform_test.rb +0 -93
  145. data/test/adapter/json_api/belongs_to_test.rb +0 -155
  146. data/test/adapter/json_api/collection_test.rb +0 -95
  147. data/test/adapter/json_api/errors_test.rb +0 -78
  148. data/test/adapter/json_api/fields_test.rb +0 -87
  149. data/test/adapter/json_api/has_many_embed_ids_test.rb +0 -43
  150. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +0 -96
  151. data/test/adapter/json_api/has_many_test.rb +0 -144
  152. data/test/adapter/json_api/has_one_test.rb +0 -80
  153. data/test/adapter/json_api/json_api_test.rb +0 -35
  154. data/test/adapter/json_api/linked_test.rb +0 -392
  155. data/test/adapter/json_api/links_test.rb +0 -93
  156. data/test/adapter/json_api/pagination_links_test.rb +0 -166
  157. data/test/adapter/json_api/parse_test.rb +0 -137
  158. data/test/adapter/json_api/relationship_test.rb +0 -161
  159. data/test/adapter/json_api/relationships_test.rb +0 -199
  160. data/test/adapter/json_api/resource_identifier_test.rb +0 -85
  161. data/test/adapter/json_api/resource_meta_test.rb +0 -100
  162. data/test/adapter/json_api/toplevel_jsonapi_test.rb +0 -82
  163. data/test/adapter/json_api/transform_test.rb +0 -502
  164. data/test/adapter/json_api/type_test.rb +0 -61
  165. data/test/adapter/json_test.rb +0 -45
  166. data/test/adapter/null_test.rb +0 -23
  167. data/test/adapter/polymorphic_test.rb +0 -171
  168. data/test/adapter_test.rb +0 -67
  169. data/test/array_serializer_test.rb +0 -22
  170. data/test/benchmark/app.rb +0 -65
  171. data/test/benchmark/benchmarking_support.rb +0 -67
  172. data/test/benchmark/bm_caching.rb +0 -119
  173. data/test/benchmark/bm_transform.rb +0 -34
  174. data/test/benchmark/config.ru +0 -3
  175. data/test/benchmark/controllers.rb +0 -84
  176. data/test/benchmark/fixtures.rb +0 -219
  177. data/test/cache_test.rb +0 -485
  178. data/test/collection_serializer_test.rb +0 -110
  179. data/test/fixtures/active_record.rb +0 -78
  180. data/test/fixtures/poro.rb +0 -282
  181. data/test/generators/scaffold_controller_generator_test.rb +0 -24
  182. data/test/generators/serializer_generator_test.rb +0 -57
  183. data/test/grape_test.rb +0 -82
  184. data/test/include_tree/from_include_args_test.rb +0 -26
  185. data/test/include_tree/from_string_test.rb +0 -94
  186. data/test/include_tree/include_args_to_hash_test.rb +0 -64
  187. data/test/lint_test.rb +0 -49
  188. data/test/logger_test.rb +0 -18
  189. data/test/poro_test.rb +0 -9
  190. data/test/serializable_resource_test.rb +0 -83
  191. data/test/serializers/association_macros_test.rb +0 -36
  192. data/test/serializers/associations_test.rb +0 -295
  193. data/test/serializers/attribute_test.rb +0 -151
  194. data/test/serializers/attributes_test.rb +0 -52
  195. data/test/serializers/caching_configuration_test_isolated.rb +0 -170
  196. data/test/serializers/configuration_test.rb +0 -32
  197. data/test/serializers/fieldset_test.rb +0 -14
  198. data/test/serializers/meta_test.rb +0 -196
  199. data/test/serializers/options_test.rb +0 -21
  200. data/test/serializers/read_attribute_for_serialization_test.rb +0 -79
  201. data/test/serializers/root_test.rb +0 -21
  202. data/test/serializers/serialization_test.rb +0 -55
  203. data/test/serializers/serializer_for_test.rb +0 -134
  204. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  205. data/test/support/isolated_unit.rb +0 -79
  206. data/test/support/rails5_shims.rb +0 -47
  207. data/test/support/rails_app.rb +0 -45
  208. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  209. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +0 -6
  210. data/test/support/schemas/custom/show.json +0 -7
  211. data/test/support/schemas/hyper_schema.json +0 -93
  212. data/test/support/schemas/render_using_json_api.json +0 -43
  213. data/test/support/schemas/simple_json_pointers.json +0 -10
  214. data/test/support/serialization_testing.rb +0 -53
  215. data/test/test_helper.rb +0 -57
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_model/serializer/field'
4
+ require 'active_model/serializer/association'
2
5
 
3
6
  module ActiveModel
4
7
  class Serializer
@@ -8,12 +11,26 @@ module ActiveModel
8
11
  # @example
9
12
  # class PostSerializer < ActiveModel::Serializer
10
13
  # has_one :author, serializer: AuthorSerializer
14
+ # belongs_to :boss, type: :users, foreign_key: :boss_id
11
15
  # has_many :comments
12
16
  # has_many :comments, key: :last_comments do
13
17
  # object.comments.last(1)
14
18
  # end
15
19
  # has_many :secret_meta_data, if: :is_admin?
16
20
  #
21
+ # has_one :blog do |serializer|
22
+ # meta count: object.roles.count
23
+ # serializer.cached_blog
24
+ # end
25
+ #
26
+ # private
27
+ #
28
+ # def cached_blog
29
+ # cache_store.fetch("cached_blog:#{object.updated_at}") do
30
+ # Blog.find(object.blog_id)
31
+ # end
32
+ # end
33
+ #
17
34
  # def is_admin?
18
35
  # current_user.admin?
19
36
  # end
@@ -23,72 +40,144 @@ module ActiveModel
23
40
  # 1) as 'comments' and named 'comments'.
24
41
  # 2) as 'object.comments.last(1)' and named 'last_comments'.
25
42
  #
26
- # PostSerializer._reflections #=>
27
- # # [
28
- # # HasOneReflection.new(:author, serializer: AuthorSerializer),
29
- # # HasManyReflection.new(:comments)
30
- # # HasManyReflection.new(:comments, { key: :last_comments }, #<Block>)
31
- # # HasManyReflection.new(:secret_meta_data, { if: :is_admin? })
32
- # # ]
43
+ # PostSerializer._reflections # =>
44
+ # # {
45
+ # # author: HasOneReflection.new(:author, serializer: AuthorSerializer),
46
+ # # comments: HasManyReflection.new(:comments)
47
+ # # last_comments: HasManyReflection.new(:comments, { key: :last_comments }, #<Block>)
48
+ # # secret_meta_data: HasManyReflection.new(:secret_meta_data, { if: :is_admin? })
49
+ # # }
33
50
  #
34
51
  # So you can inspect reflections in your Adapters.
35
- #
36
52
  class Reflection < Field
53
+ attr_reader :foreign_key, :type
54
+
37
55
  def initialize(*)
38
56
  super
39
- @_links = {}
40
- @_include_data = true
41
- @_meta = nil
57
+ options[:links] = {}
58
+ options[:include_data_setting] = Serializer.config.include_data_default
59
+ options[:meta] = nil
60
+ @type = options.fetch(:type) do
61
+ class_name = options.fetch(:class_name, name.to_s.camelize.singularize)
62
+ class_name.underscore.pluralize.to_sym
63
+ end
64
+ @foreign_key = options.fetch(:foreign_key) do
65
+ if collection?
66
+ "#{name.to_s.singularize}_ids".to_sym
67
+ else
68
+ "#{name}_id".to_sym
69
+ end
70
+ end
42
71
  end
43
72
 
73
+ # @api public
74
+ # @example
75
+ # has_one :blog do
76
+ # include_data false
77
+ # link :self, 'a link'
78
+ # link :related, 'another link'
79
+ # link :self, '//example.com/link_author/relationships/bio'
80
+ # id = object.profile.id
81
+ # link :related do
82
+ # "//example.com/profiles/#{id}" if id != 123
83
+ # end
84
+ # link :related do
85
+ # ids = object.likes.map(&:id).join(',')
86
+ # href "//example.com/likes/#{ids}"
87
+ # meta ids: ids
88
+ # end
89
+ # end
44
90
  def link(name, value = nil, &block)
45
- @_links[name] = block || value
91
+ options[:links][name] = block_given? ? block : value
46
92
  :nil
47
93
  end
48
94
 
95
+ # @api public
96
+ # @example
97
+ # has_one :blog do
98
+ # include_data false
99
+ # meta(id: object.blog.id)
100
+ # meta liked: object.likes.any?
101
+ # link :self do
102
+ # href object.blog.id.to_s
103
+ # meta(id: object.blog.id)
104
+ # end
49
105
  def meta(value = nil, &block)
50
- @_meta = block || value
106
+ options[:meta] = block_given? ? block : value
51
107
  :nil
52
108
  end
53
109
 
110
+ # @api public
111
+ # @example
112
+ # has_one :blog do
113
+ # include_data false
114
+ # link :self, 'a link'
115
+ # link :related, 'another link'
116
+ # end
117
+ #
118
+ # has_one :blog do
119
+ # include_data false
120
+ # link :self, 'a link'
121
+ # link :related, 'another link'
122
+ # end
123
+ #
124
+ # belongs_to :reviewer do
125
+ # meta name: 'Dan Brown'
126
+ # include_data true
127
+ # end
128
+ #
129
+ # has_many :tags, serializer: TagSerializer do
130
+ # link :self, '//example.com/link_author/relationships/tags'
131
+ # include_data :if_sideloaded
132
+ # end
54
133
  def include_data(value = true)
55
- @_include_data = value
134
+ options[:include_data_setting] = value
56
135
  :nil
57
136
  end
58
137
 
138
+ def collection?
139
+ false
140
+ end
141
+
142
+ def include_data?(include_slice)
143
+ include_data_setting = options[:include_data_setting]
144
+ case include_data_setting
145
+ when :if_sideloaded then include_slice.key?(options.fetch(:key, name))
146
+ when true then true
147
+ when false then false
148
+ else fail ArgumentError, "Unknown include_data_setting '#{include_data_setting.inspect}'"
149
+ end
150
+ end
151
+
59
152
  # @param serializer [ActiveModel::Serializer]
60
153
  # @yield [ActiveModel::Serializer]
61
154
  # @return [:nil, associated resource or resource collection]
62
- # @example
63
- # has_one :blog do |serializer|
64
- # serializer.cached_blog
65
- # end
66
- #
67
- # def cached_blog
68
- # cache_store.fetch("cached_blog:#{object.updated_at}") do
69
- # Blog.find(object.blog_id)
70
- # end
71
- # end
72
- def value(serializer)
155
+ def value(serializer, include_slice)
156
+ # NOTE(BF): This method isn't thread-safe because the _reflections class attribute is not thread-safe
157
+ # Therefore, when we build associations from reflections, we dup the entire reflection instance.
158
+ # Better solutions much appreciated!
73
159
  @object = serializer.object
74
160
  @scope = serializer.scope
75
161
 
76
- if block
77
- block_value = instance_exec(serializer, &block)
78
- if block_value == :nil
79
- serializer.read_attribute_for_serialization(name)
80
- else
81
- block_value
82
- end
162
+ block_value = instance_exec(serializer, &block) if block
163
+ return unless include_data?(include_slice)
164
+
165
+ if block && block_value != :nil
166
+ block_value
83
167
  else
84
168
  serializer.read_attribute_for_serialization(name)
85
169
  end
86
170
  end
87
171
 
172
+ # @api private
173
+ def foreign_key_on
174
+ :related
175
+ end
176
+
88
177
  # Build association. This method is used internally to
89
178
  # build serializer's association by its reflection.
90
179
  #
91
- # @param [Serializer] subject is a parent serializer for given association
180
+ # @param [Serializer] parent_serializer for given association
92
181
  # @param [Hash{Symbol => Object}] parent_serializer_options
93
182
  #
94
183
  # @example
@@ -105,43 +194,19 @@ module ActiveModel
105
194
  # comments_reflection.build_association(post_serializer, foo: 'bar')
106
195
  #
107
196
  # @api private
108
- #
109
- def build_association(subject, parent_serializer_options)
110
- association_value = value(subject)
111
- reflection_options = options.dup
112
- serializer_class = subject.class.serializer_for(association_value, reflection_options)
113
- reflection_options[:include_data] = @_include_data
114
-
115
- if serializer_class
116
- begin
117
- serializer = serializer_class.new(
118
- association_value,
119
- serializer_options(subject, parent_serializer_options, reflection_options)
120
- )
121
- rescue ActiveModel::Serializer::CollectionSerializer::NoSerializerError
122
- reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
123
- end
124
- elsif !association_value.nil? && !association_value.instance_of?(Object)
125
- reflection_options[:virtual_value] = association_value
126
- end
127
-
128
- Association.new(name, serializer, reflection_options, @_links, @_meta)
197
+ def build_association(parent_serializer, parent_serializer_options, include_slice = {})
198
+ association_options = {
199
+ parent_serializer: parent_serializer,
200
+ parent_serializer_options: parent_serializer_options,
201
+ include_slice: include_slice
202
+ }
203
+ Association.new(self, association_options)
129
204
  end
130
205
 
131
206
  protected
132
207
 
208
+ # used in instance exec
133
209
  attr_accessor :object, :scope
134
-
135
- private
136
-
137
- def serializer_options(subject, parent_serializer_options, reflection_options)
138
- serializer = reflection_options.fetch(:serializer, nil)
139
-
140
- serializer_options = parent_serializer_options.except(:serializer)
141
- serializer_options[:serializer] = serializer if serializer
142
- serializer_options[:serializer_context_class] = subject.class
143
- serializer_options
144
- end
145
210
  end
146
211
  end
147
212
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveModel
2
4
  class Serializer
3
- VERSION = '0.10.0'.freeze
5
+ VERSION = '0.10.13'.freeze
4
6
  end
5
7
  end