active_model_serializers 0.10.0 → 0.10.2

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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -4
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +39 -2
  5. data/Gemfile +1 -1
  6. data/README.md +21 -24
  7. data/Rakefile +3 -3
  8. data/active_model_serializers.gemspec +19 -23
  9. data/docs/general/adapters.md +4 -2
  10. data/docs/general/configuration_options.md +6 -1
  11. data/docs/general/deserialization.md +1 -1
  12. data/docs/general/fields.md +31 -0
  13. data/docs/general/rendering.md +7 -2
  14. data/docs/general/serializers.md +62 -3
  15. data/docs/howto/add_pagination_links.md +2 -3
  16. data/docs/integrations/ember-and-json-api.md +25 -10
  17. data/docs/jsonapi/schema.md +1 -1
  18. data/lib/action_controller/serialization.rb +4 -3
  19. data/lib/active_model/serializer/adapter/base.rb +2 -0
  20. data/lib/active_model/serializer/array_serializer.rb +8 -5
  21. data/lib/active_model/serializer/associations.rb +6 -7
  22. data/lib/active_model/serializer/belongs_to_reflection.rb +0 -3
  23. data/lib/active_model/serializer/caching.rb +67 -112
  24. data/lib/active_model/serializer/collection_serializer.rb +30 -10
  25. data/lib/active_model/serializer/configuration.rb +1 -0
  26. data/lib/active_model/serializer/error_serializer.rb +11 -7
  27. data/lib/active_model/serializer/errors_serializer.rb +25 -20
  28. data/lib/active_model/serializer/has_many_reflection.rb +0 -3
  29. data/lib/active_model/serializer/has_one_reflection.rb +0 -3
  30. data/lib/active_model/serializer/lint.rb +134 -130
  31. data/lib/active_model/serializer/reflection.rb +3 -3
  32. data/lib/active_model/serializer/version.rb +1 -1
  33. data/lib/active_model/serializer.rb +57 -15
  34. data/lib/active_model_serializers/adapter/attributes.rb +2 -67
  35. data/lib/active_model_serializers/adapter/base.rb +38 -38
  36. data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
  37. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +8 -1
  38. data/lib/active_model_serializers/adapter/json_api.rb +36 -28
  39. data/lib/active_model_serializers/adapter.rb +6 -0
  40. data/lib/active_model_serializers/deprecate.rb +1 -2
  41. data/lib/active_model_serializers/deserialization.rb +2 -0
  42. data/lib/active_model_serializers/model.rb +3 -1
  43. data/lib/active_model_serializers/railtie.rb +3 -1
  44. data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
  45. data/lib/active_model_serializers/serialization_context.rb +10 -3
  46. data/lib/active_model_serializers.rb +6 -0
  47. data/lib/generators/rails/serializer_generator.rb +3 -3
  48. data/lib/grape/active_model_serializers.rb +7 -5
  49. data/lib/grape/formatters/active_model_serializers.rb +19 -2
  50. data/lib/grape/helpers/active_model_serializers.rb +1 -0
  51. data/test/action_controller/adapter_selector_test.rb +4 -4
  52. data/test/action_controller/explicit_serializer_test.rb +5 -4
  53. data/test/action_controller/json/include_test.rb +106 -27
  54. data/test/action_controller/json_api/errors_test.rb +6 -7
  55. data/test/action_controller/json_api/linked_test.rb +29 -24
  56. data/test/action_controller/json_api/pagination_test.rb +19 -19
  57. data/test/action_controller/serialization_test.rb +10 -7
  58. data/test/active_model_serializers/json_pointer_test.rb +15 -13
  59. data/test/active_model_serializers/key_transform_test.rb +254 -252
  60. data/test/active_model_serializers/model_test.rb +6 -4
  61. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +143 -0
  62. data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
  63. data/test/adapter/json/collection_test.rb +14 -0
  64. data/test/adapter/json/transform_test.rb +14 -14
  65. data/test/adapter/json_api/collection_test.rb +4 -3
  66. data/test/adapter/json_api/errors_test.rb +17 -19
  67. data/test/adapter/json_api/has_many_test.rb +18 -18
  68. data/test/adapter/json_api/json_api_test.rb +5 -7
  69. data/test/adapter/json_api/linked_test.rb +9 -6
  70. data/test/adapter/json_api/links_test.rb +3 -1
  71. data/test/adapter/json_api/pagination_links_test.rb +19 -7
  72. data/test/adapter/json_api/relationships_test.rb +9 -4
  73. data/test/adapter/json_api/resource_identifier_test.rb +7 -2
  74. data/test/adapter/json_api/resource_meta_test.rb +3 -3
  75. data/test/adapter/json_api/transform_test.rb +251 -250
  76. data/test/adapter/json_api/type_test.rb +1 -1
  77. data/test/adapter/json_test.rb +8 -7
  78. data/test/adapter/null_test.rb +1 -2
  79. data/test/adapter/polymorphic_test.rb +5 -5
  80. data/test/adapter_test.rb +1 -1
  81. data/test/benchmark/app.rb +1 -1
  82. data/test/benchmark/bm_caching.rb +15 -15
  83. data/test/benchmark/bm_transform.rb +16 -5
  84. data/test/benchmark/controllers.rb +16 -17
  85. data/test/benchmark/fixtures.rb +72 -72
  86. data/test/cache_test.rb +101 -45
  87. data/test/collection_serializer_test.rb +2 -2
  88. data/test/fixtures/poro.rb +8 -7
  89. data/test/grape_test.rb +152 -56
  90. data/test/lint_test.rb +1 -1
  91. data/test/logger_test.rb +13 -11
  92. data/test/serializable_resource_test.rb +18 -22
  93. data/test/serializers/associations_test.rb +10 -10
  94. data/test/serializers/attribute_test.rb +1 -1
  95. data/test/serializers/attributes_test.rb +1 -1
  96. data/test/serializers/fieldset_test.rb +1 -1
  97. data/test/serializers/meta_test.rb +12 -6
  98. data/test/serializers/root_test.rb +1 -1
  99. data/test/serializers/serializer_for_test.rb +3 -1
  100. data/test/support/isolated_unit.rb +5 -2
  101. data/test/support/rails5_shims.rb +8 -2
  102. data/test/support/rails_app.rb +0 -9
  103. data/test/support/serialization_testing.rb +7 -5
  104. metadata +54 -24
  105. data/.rubocop_todo.yml +0 -167
  106. data/lib/active_model/serializer/include_tree.rb +0 -111
  107. data/test/include_tree/from_include_args_test.rb +0 -26
  108. data/test/include_tree/from_string_test.rb +0 -94
  109. data/test/include_tree/include_args_to_hash_test.rb +0 -64
@@ -31,16 +31,27 @@ module ActiveModelSerializers
31
31
  autoload :Error
32
32
  autoload :Deserialization
33
33
 
34
+ def self.default_key_transform
35
+ :dash
36
+ end
37
+
38
+ def self.fragment_cache(cached_hash, non_cached_hash, root = true)
39
+ core_cached = cached_hash.first
40
+ core_non_cached = non_cached_hash.first
41
+ no_root_cache = cached_hash.delete_if { |key, _value| key == core_cached[0] }
42
+ no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] }
43
+ cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
44
+ hash = root ? { root => cached_resource } : cached_resource
45
+
46
+ hash.deep_merge no_root_non_cache.deep_merge no_root_cache
47
+ end
48
+
34
49
  def initialize(serializer, options = {})
35
50
  super
36
- @include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(options[:include])
51
+ @include_directive = JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
37
52
  @fieldset = options[:fieldset] || ActiveModel::Serializer::Fieldset.new(options.delete(:fields))
38
53
  end
39
54
 
40
- def self.default_key_transform
41
- :dash
42
- end
43
-
44
55
  # {http://jsonapi.org/format/#crud Requests are transactional, i.e. success or failure}
45
56
  # {http://jsonapi.org/format/#document-top-level data and errors MUST NOT coexist in the same document.}
46
57
  def serializable_hash(*)
@@ -52,6 +63,11 @@ module ActiveModelSerializers
52
63
  self.class.transform_key_casing!(document, instance_options)
53
64
  end
54
65
 
66
+ def fragment_cache(cached_hash, non_cached_hash)
67
+ root = !instance_options.include?(:include)
68
+ self.class.fragment_cache(cached_hash, non_cached_hash, root)
69
+ end
70
+
55
71
  # {http://jsonapi.org/format/#document-top-level Primary data}
56
72
  # definition:
57
73
  # ☐ toplevel_data (required)
@@ -174,18 +190,6 @@ module ActiveModelSerializers
174
190
  hash
175
191
  end
176
192
 
177
- def fragment_cache(cached_hash, non_cached_hash)
178
- root = false if instance_options.include?(:include)
179
- core_cached = cached_hash.first
180
- core_non_cached = non_cached_hash.first
181
- no_root_cache = cached_hash.delete_if { |key, _value| key == core_cached[0] }
182
- no_root_non_cache = non_cached_hash.delete_if { |key, _value| key == core_non_cached[0] }
183
- cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
184
- hash = root ? { root => cached_resource } : cached_resource
185
-
186
- hash.deep_merge no_root_non_cache.deep_merge no_root_cache
187
- end
188
-
189
193
  protected
190
194
 
191
195
  attr_reader :fieldset
@@ -232,7 +236,7 @@ module ActiveModelSerializers
232
236
  @included = []
233
237
  @resource_identifiers = Set.new
234
238
  serializers.each { |serializer| process_resource(serializer, true) }
235
- serializers.each { |serializer| process_relationships(serializer, @include_tree) }
239
+ serializers.each { |serializer| process_relationships(serializer, @include_directive) }
236
240
 
237
241
  [@primary, @included]
238
242
  end
@@ -251,21 +255,21 @@ module ActiveModelSerializers
251
255
  true
252
256
  end
253
257
 
254
- def process_relationships(serializer, include_tree)
255
- serializer.associations(include_tree).each do |association|
256
- process_relationship(association.serializer, include_tree[association.key])
258
+ def process_relationships(serializer, include_directive)
259
+ serializer.associations(include_directive).each do |association|
260
+ process_relationship(association.serializer, include_directive[association.key])
257
261
  end
258
262
  end
259
263
 
260
- def process_relationship(serializer, include_tree)
264
+ def process_relationship(serializer, include_directive)
261
265
  if serializer.respond_to?(:each)
262
- serializer.each { |s| process_relationship(s, include_tree) }
266
+ serializer.each { |s| process_relationship(s, include_directive) }
263
267
  return
264
268
  end
265
269
  return unless serializer && serializer.object
266
270
  return unless process_resource(serializer, false)
267
271
 
268
- process_relationships(serializer, include_tree)
272
+ process_relationships(serializer, include_directive)
269
273
  end
270
274
 
271
275
  # {http://jsonapi.org/format/#document-resource-object-attributes Document Resource Object Attributes}
@@ -290,7 +294,7 @@ module ActiveModelSerializers
290
294
 
291
295
  # {http://jsonapi.org/format/#document-resource-objects Document Resource Objects}
292
296
  def resource_object_for(serializer)
293
- resource_object = cache_check(serializer) do
297
+ resource_object = serializer.fetch(self) do
294
298
  resource_object = ResourceIdentifier.new(serializer, instance_options).as_json
295
299
 
296
300
  requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
@@ -429,8 +433,11 @@ module ActiveModelSerializers
429
433
  # meta: meta
430
434
  # }.reject! {|_,v| v.nil? }
431
435
  def relationships_for(serializer, requested_associations)
432
- include_tree = ActiveModel::Serializer::IncludeTree.from_include_args(requested_associations)
433
- serializer.associations(include_tree).each_with_object({}) do |association, hash|
436
+ include_directive = JSONAPI::IncludeDirective.new(
437
+ requested_associations,
438
+ allow_wildcard: true
439
+ )
440
+ serializer.associations(include_directive).each_with_object({}) do |association, hash|
434
441
  hash[association.key] = Relationship.new(
435
442
  serializer,
436
443
  association.serializer,
@@ -467,7 +474,8 @@ module ActiveModelSerializers
467
474
  # }.reject! {|_,v| v.nil? }
468
475
  def links_for(serializer)
469
476
  serializer._links.each_with_object({}) do |(name, value), hash|
470
- hash[name] = Link.new(serializer, value).as_json
477
+ result = Link.new(serializer, value).as_json
478
+ hash[name] = result if result
471
479
  end
472
480
  end
473
481
 
@@ -5,11 +5,13 @@ module ActiveModelSerializers
5
5
  private_constant :ADAPTER_MAP if defined?(private_constant)
6
6
 
7
7
  class << self # All methods are class functions
8
+ # :nocov:
8
9
  def new(*args)
9
10
  fail ArgumentError, 'Adapters inherit from Adapter::Base.' \
10
11
  "Adapter.new called with args: '#{args.inspect}', from" \
11
12
  "'caller[0]'."
12
13
  end
14
+ # :nocov:
13
15
 
14
16
  def configured_adapter
15
17
  lookup(ActiveModelSerializers.config.adapter)
@@ -51,6 +53,10 @@ module ActiveModelSerializers
51
53
  self
52
54
  end
53
55
 
56
+ def registered_name(adapter_class)
57
+ ADAPTER_MAP.key adapter_class
58
+ end
59
+
54
60
  # @param adapter [String, Symbol, Class] name to fetch adapter by
55
61
  # @return [ActiveModelSerializers::Adapter] subclass of Adapter
56
62
  # @raise [UnknownAdapterError]
@@ -36,8 +36,7 @@ module ActiveModelSerializers
36
36
  target = is_a?(Module) ? "#{self}." : "#{self.class}#"
37
37
  msg = ["NOTE: #{target}#{name} is deprecated",
38
38
  replacement == :none ? ' with no replacement' : "; use #{replacement} instead",
39
- "\n#{target}#{name} called from #{ActiveModelSerializers.location_of_caller.join(":")}"
40
- ]
39
+ "\n#{target}#{name} called from #{ActiveModelSerializers.location_of_caller.join(':')}"]
41
40
  warn "#{msg.join}."
42
41
  send old, *args, &block
43
42
  end
@@ -6,8 +6,10 @@ module ActiveModelSerializers
6
6
  Adapter::JsonApi::Deserialization.parse(*args)
7
7
  end
8
8
 
9
+ # :nocov:
9
10
  def jsonapi_parse!(*args)
10
11
  Adapter::JsonApi::Deserialization.parse!(*args)
11
12
  end
13
+ # :nocov:
12
14
  end
13
15
  end
@@ -21,7 +21,7 @@ module ActiveModelSerializers
21
21
 
22
22
  # Defaults to the downcased model name and updated_at
23
23
  def cache_key
24
- attributes.fetch(:cache_key) { "#{self.class.name.downcase}/#{id}-#{updated_at.strftime("%Y%m%d%H%M%S%9N")}" }
24
+ attributes.fetch(:cache_key) { "#{self.class.name.downcase}/#{id}-#{updated_at.strftime('%Y%m%d%H%M%S%9N')}" }
25
25
  end
26
26
 
27
27
  # Defaults to the time the serializer file was modified.
@@ -38,6 +38,7 @@ module ActiveModelSerializers
38
38
  end
39
39
 
40
40
  # The following methods are needed to be minimally implemented for ActiveModel::Errors
41
+ # :nocov:
41
42
  def self.human_attribute_name(attr, _options = {})
42
43
  attr
43
44
  end
@@ -45,5 +46,6 @@ module ActiveModelSerializers
45
46
  def self.lookup_ancestors
46
47
  [self]
47
48
  end
49
+ # :nocov:
48
50
  end
49
51
  end
@@ -23,7 +23,7 @@ module ActiveModelSerializers
23
23
  # This hook is run after the action_controller railtie has set the configuration
24
24
  # based on the *environment* configuration and before any config/initializers are run
25
25
  # and also before eager_loading (if enabled).
26
- initializer 'active_model_serializers.set_configs', :after => 'action_controller.set_configs' do
26
+ initializer 'active_model_serializers.set_configs', after: 'action_controller.set_configs' do
27
27
  ActiveModelSerializers.logger = Rails.configuration.action_controller.logger
28
28
  ActiveModelSerializers.config.perform_caching = Rails.configuration.action_controller.perform_caching
29
29
  # We want this hook to run after the config has been set, even if ActionController has already loaded.
@@ -32,11 +32,13 @@ module ActiveModelSerializers
32
32
  end
33
33
  end
34
34
 
35
+ # :nocov:
35
36
  generators do |app|
36
37
  Rails::Generators.configure!(app.config.generators)
37
38
  Rails::Generators.hidden_namespaces.uniq!
38
39
  require 'generators/rails/resource_override'
39
40
  end
41
+ # :nocov:
40
42
 
41
43
  if Rails.env.test?
42
44
  ActionController::TestCase.send(:include, ActiveModelSerializers::Test::Schema)
@@ -22,44 +22,57 @@
22
22
  # render jsonapi: model
23
23
  #
24
24
  # No wrapper format needed as it does not apply (i.e. no `wrap_parameters format: [jsonapi]`)
25
+ module ActiveModelSerializers
26
+ module Jsonapi
27
+ MEDIA_TYPE = 'application/vnd.api+json'.freeze
28
+ HEADERS = {
29
+ response: { 'CONTENT_TYPE'.freeze => MEDIA_TYPE },
30
+ request: { 'ACCEPT'.freeze => MEDIA_TYPE }
31
+ }.freeze
25
32
 
26
- module ActiveModelSerializers::Jsonapi
27
- MEDIA_TYPE = 'application/vnd.api+json'.freeze
28
- HEADERS = {
29
- response: { 'CONTENT_TYPE'.freeze => MEDIA_TYPE },
30
- request: { 'ACCEPT'.freeze => MEDIA_TYPE }
31
- }.freeze
32
- module ControllerSupport
33
- def serialize_jsonapi(json, options)
34
- options[:adapter] = :json_api
35
- options.fetch(:serialization_context) { options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request) }
36
- get_serializer(json, options)
37
- end
38
- end
39
- end
33
+ def self.install
34
+ # actionpack/lib/action_dispatch/http/mime_types.rb
35
+ Mime::Type.register MEDIA_TYPE, :jsonapi
40
36
 
41
- # actionpack/lib/action_dispatch/http/mime_types.rb
42
- Mime::Type.register ActiveModelSerializers::Jsonapi::MEDIA_TYPE, :jsonapi
37
+ if Rails::VERSION::MAJOR >= 5
38
+ ActionDispatch::Request.parameter_parsers[:jsonapi] = parser
39
+ else
40
+ ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime[:jsonapi]] = parser
41
+ end
43
42
 
44
- parsers = Rails::VERSION::MAJOR >= 5 ? ActionDispatch::Http::Parameters : ActionDispatch::ParamsParser
45
- media_type = Mime::Type.lookup(ActiveModelSerializers::Jsonapi::MEDIA_TYPE)
43
+ # ref https://github.com/rails/rails/pull/21496
44
+ ActionController::Renderers.add :jsonapi do |json, options|
45
+ json = serialize_jsonapi(json, options).to_json(options) unless json.is_a?(String)
46
+ self.content_type ||= Mime[:jsonapi]
47
+ self.response_body = json
48
+ end
49
+ end
46
50
 
47
- # Proposal: should actually deserialize the JSON API params
48
- # to the hash format expected by `ActiveModel::Serializers::JSON`
49
- # actionpack/lib/action_dispatch/http/parameters.rb
50
- parsers::DEFAULT_PARSERS[media_type] = lambda do |body|
51
- data = JSON.parse(body)
52
- data = { :_json => data } unless data.is_a?(Hash)
53
- data.with_indifferent_access
54
- end
51
+ # Proposal: should actually deserialize the JSON API params
52
+ # to the hash format expected by `ActiveModel::Serializers::JSON`
53
+ # actionpack/lib/action_dispatch/http/parameters.rb
54
+ def self.parser
55
+ lambda do |body|
56
+ data = JSON.parse(body)
57
+ data = { _json: data } unless data.is_a?(Hash)
58
+ data.with_indifferent_access
59
+ end
60
+ end
55
61
 
56
- # ref https://github.com/rails/rails/pull/21496
57
- ActionController::Renderers.add :jsonapi do |json, options|
58
- json = serialize_jsonapi(json, options).to_json(options) unless json.is_a?(String)
59
- self.content_type ||= media_type
60
- self.response_body = json
62
+ module ControllerSupport
63
+ def serialize_jsonapi(json, options)
64
+ options[:adapter] = :json_api
65
+ options.fetch(:serialization_context) do
66
+ options[:serialization_context] = ActiveModelSerializers::SerializationContext.new(request)
67
+ end
68
+ get_serializer(json, options)
69
+ end
70
+ end
71
+ end
61
72
  end
62
73
 
74
+ ActiveModelSerializers::Jsonapi.install
75
+
63
76
  ActiveSupport.on_load(:action_controller) do
64
77
  include ActiveModelSerializers::Jsonapi::ControllerSupport
65
78
  end
@@ -1,3 +1,4 @@
1
+ require 'active_support/core_ext/array/extract_options'
1
2
  module ActiveModelSerializers
2
3
  class SerializationContext
3
4
  class << self
@@ -22,9 +23,15 @@ module ActiveModelSerializers
22
23
 
23
24
  attr_reader :request_url, :query_parameters, :key_transform
24
25
 
25
- def initialize(request, options = {})
26
- @request_url = request.original_url[/\A[^?]+/]
27
- @query_parameters = request.query_parameters
26
+ def initialize(*args)
27
+ options = args.extract_options!
28
+ if args.size == 1
29
+ request = args.pop
30
+ options[:request_url] = request.original_url[/\A[^?]+/]
31
+ options[:query_parameters] = request.query_parameters
32
+ end
33
+ @request_url = options.delete(:request_url)
34
+ @query_parameters = options.delete(:query_parameters)
28
35
  @url_helpers = options.delete(:url_helpers) || self.class.url_helpers
29
36
  @default_url_options = options.delete(:default_url_options) || self.class.default_url_options
30
37
  end
@@ -31,6 +31,12 @@ module ActiveModelSerializers
31
31
  [file, lineno]
32
32
  end
33
33
 
34
+ # Memoized default include directive
35
+ # @return [JSONAPI::IncludeDirective]
36
+ def self.default_include_directive
37
+ @default_include_directive ||= JSONAPI::IncludeDirective.new(config.default_includes, allow_wildcard: true)
38
+ end
39
+
34
40
  require 'active_model/serializer/version'
35
41
  require 'active_model/serializer'
36
42
  require 'active_model/serializable_resource'
@@ -2,11 +2,11 @@ module Rails
2
2
  module Generators
3
3
  class SerializerGenerator < NamedBase
4
4
  source_root File.expand_path('../templates', __FILE__)
5
- check_class_collision :suffix => 'Serializer'
5
+ check_class_collision suffix: 'Serializer'
6
6
 
7
- argument :attributes, :type => :array, :default => [], :banner => 'field:type field:type'
7
+ argument :attributes, type: :array, default: [], banner: 'field:type field:type'
8
8
 
9
- class_option :parent, :type => :string, :desc => 'The parent class for the generated serializer'
9
+ class_option :parent, type: :string, desc: 'The parent class for the generated serializer'
10
10
 
11
11
  def create_serializer_file
12
12
  template 'serializer.rb.erb', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
@@ -4,11 +4,13 @@ require 'active_model_serializers'
4
4
  require 'grape/formatters/active_model_serializers'
5
5
  require 'grape/helpers/active_model_serializers'
6
6
 
7
- module Grape::ActiveModelSerializers
8
- extend ActiveSupport::Concern
7
+ module Grape
8
+ module ActiveModelSerializers
9
+ extend ActiveSupport::Concern
9
10
 
10
- included do
11
- formatter :json, Grape::Formatters::ActiveModelSerializers
12
- helpers Grape::Helpers::ActiveModelSerializers
11
+ included do
12
+ formatter :json, Grape::Formatters::ActiveModelSerializers
13
+ helpers Grape::Helpers::ActiveModelSerializers
14
+ end
13
15
  end
14
16
  end
@@ -2,14 +2,31 @@
2
2
  #
3
3
  # Serializer options can be passed as a hash from your Grape endpoint using env[:active_model_serializer_options],
4
4
  # or better yet user the render helper in Grape::Helpers::ActiveModelSerializers
5
+
6
+ require 'active_model_serializers/serialization_context'
7
+
5
8
  module Grape
6
9
  module Formatters
7
10
  module ActiveModelSerializers
8
11
  def self.call(resource, env)
9
- serializer_options = {}
10
- serializer_options.merge!(env[:active_model_serializer_options]) if env[:active_model_serializer_options]
12
+ serializer_options = build_serializer_options(env)
11
13
  ::ActiveModelSerializers::SerializableResource.new(resource, serializer_options).to_json
12
14
  end
15
+
16
+ def self.build_serializer_options(env)
17
+ ams_options = env[:active_model_serializer_options] || {}
18
+
19
+ # Add serialization context
20
+ ams_options.fetch(:serialization_context) do
21
+ request = env['grape.request']
22
+ ams_options[:serialization_context] = ::ActiveModelSerializers::SerializationContext.new(
23
+ request_url: request.url[/\A[^?]+/],
24
+ query_parameters: request.params
25
+ )
26
+ end
27
+
28
+ ams_options
29
+ end
13
30
  end
14
31
  end
15
32
  end
@@ -1,4 +1,5 @@
1
1
  # Helpers can be included in your Grape endpoint as: helpers Grape::Helpers::ActiveModelSerializers
2
+
2
3
  module Grape
3
4
  module Helpers
4
5
  module ActiveModelSerializers
@@ -5,17 +5,17 @@ module ActionController
5
5
  class AdapterSelectorTest < ActionController::TestCase
6
6
  class AdapterSelectorTestController < ActionController::Base
7
7
  def render_using_default_adapter
8
- @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
8
+ @profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
9
9
  render json: @profile
10
10
  end
11
11
 
12
12
  def render_using_adapter_override
13
- @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
13
+ @profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
14
14
  render json: @profile, adapter: :json_api
15
15
  end
16
16
 
17
17
  def render_skipping_adapter
18
- @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
18
+ @profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
19
19
  render json: @profile, adapter: false
20
20
  end
21
21
  end
@@ -32,7 +32,7 @@ module ActionController
32
32
 
33
33
  expected = {
34
34
  data: {
35
- id: assigns(:profile).id.to_s,
35
+ id: @controller.instance_variable_get(:@profile).id.to_s,
36
36
  type: 'profiles',
37
37
  attributes: {
38
38
  name: 'Name 1',
@@ -100,11 +100,12 @@ module ActionController
100
100
  get :render_array_using_explicit_serializer_and_custom_serializers
101
101
 
102
102
  expected = [
103
- { 'title' => 'New Post',
103
+ {
104
+ 'title' => 'New Post',
104
105
  'body' => 'Body',
105
- 'id' => assigns(:post).id,
106
+ 'id' => @controller.instance_variable_get(:@post).id,
106
107
  'comments' => [{ 'id' => 1 }, { 'id' => 2 }],
107
- 'author' => { 'id' => assigns(:author).id }
108
+ 'author' => { 'id' => @controller.instance_variable_get(:@author).id }
108
109
  }
109
110
  ]
110
111
 
@@ -122,7 +123,7 @@ module ActionController
122
123
  id: 42,
123
124
  lat: '-23.550520',
124
125
  lng: '-46.633309',
125
- place: 'Nowhere' # is a virtual attribute on LocationSerializer
126
+ address: 'Nowhere' # is a virtual attribute on LocationSerializer
126
127
  }
127
128
  ]
128
129
  }