From fdc7a9a52671bddf49dd025e2f6ff573e0ce5e4b Mon Sep 17 00:00:00 2001 From: Fletcher91 Date: Tue, 2 May 2017 17:09:57 +0200 Subject: [PATCH] Introduces per-request adapter switching based on the request mime. --- CHANGELOG.md | 2 ++ docs/general/adapters.md | 14 ++++++++++++++ lib/active_model_serializers/adapter.rb | 5 +++++ .../serialization_context.rb | 4 +++- test/adapter/json/transform_test.rb | 1 + test/adapter/json_api/pagination_links_test.rb | 1 + test/adapter_test.rb | 10 ++++++++++ 7 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c975e4733..8a51a85d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Breaking changes: Features: +- [#2122](https://github.com/rails-api/active_model_serializers/pull/2122) Introduces per-request adapter switching based on the request mime. (@fletcher91) + Fixes: Misc: diff --git a/docs/general/adapters.md b/docs/general/adapters.md index 84fc4e627..db6e3bcaa 100644 --- a/docs/general/adapters.md +++ b/docs/general/adapters.md @@ -36,6 +36,20 @@ The `Attributes` adapter does not include a root key. It is just the serialized Use either the `JSON` or `JSON API` adapters if you want the response document to have a root key. +To automatically switch between adapters based on the request, set the adapter to `:mime` + +```ruby + # In configuration + ActiveModelSerializers.config.adapter = :mime + + # In controller action + respond_to do |format| + format.json { render json: Model.first } # Uses the JSON adapter + format.json_api { render json: Model.first } # Users the JSON:API adapter + format.bug { render json: Model.first } # Will raise `UnknownAdapterError` + end +``` + ## Built in Adapters ### Attributes - Default diff --git a/lib/active_model_serializers/adapter.rb b/lib/active_model_serializers/adapter.rb index 98caab44f..158cd5240 100644 --- a/lib/active_model_serializers/adapter.rb +++ b/lib/active_model_serializers/adapter.rb @@ -19,6 +19,11 @@ def configured_adapter def create(resource, options = {}) override = options.delete(:adapter) + context = options[:serialization_context] + format = context && context.format + if format && (override || ActiveModelSerializers.config.adapter) == :mime + override = lookup(format) + end klass = override ? adapter_class(override) : configured_adapter klass.new(resource, options) end diff --git a/lib/active_model_serializers/serialization_context.rb b/lib/active_model_serializers/serialization_context.rb index 9ef604f2e..71bb6c2dd 100644 --- a/lib/active_model_serializers/serialization_context.rb +++ b/lib/active_model_serializers/serialization_context.rb @@ -21,15 +21,17 @@ def default_url_options end end - attr_reader :request_url, :query_parameters, :key_transform + attr_reader :request_url, :query_parameters, :key_transform, :format def initialize(*args) options = args.extract_options! if args.size == 1 request = args.pop + options[:format] = request.format.to_sym options[:request_url] = request.original_url[/\A[^?]+/] options[:query_parameters] = request.query_parameters end + @format = options.delete(:format) @request_url = options.delete(:request_url) @query_parameters = options.delete(:query_parameters) @url_helpers = options.delete(:url_helpers) || self.class.url_helpers diff --git a/test/adapter/json/transform_test.rb b/test/adapter/json/transform_test.rb index c102b5af1..a4f3e9b22 100644 --- a/test/adapter/json/transform_test.rb +++ b/test/adapter/json/transform_test.rb @@ -8,6 +8,7 @@ def mock_request(key_transform = nil) context = Minitest::Mock.new context.expect(:request_url, URI) context.expect(:query_parameters, {}) + context.expect(:format, Mime::Type.new(:api)) options = {} options[:key_transform] = key_transform if key_transform options[:serialization_context] = context diff --git a/test/adapter/json_api/pagination_links_test.rb b/test/adapter/json_api/pagination_links_test.rb index 736ea2fe2..2bfedc420 100644 --- a/test/adapter/json_api/pagination_links_test.rb +++ b/test/adapter/json_api/pagination_links_test.rb @@ -26,6 +26,7 @@ def mock_request(query_parameters = {}, original_url = URI) context.expect(:request_url, original_url) context.expect(:query_parameters, query_parameters) context.expect(:key_transform, nil) + context.expect(:format, Mime::Type.new(:json_api)) end def load_adapter(paginated_collection, mock_request = nil) diff --git a/test/adapter_test.rb b/test/adapter_test.rb index c1b00d726..b41f22c5e 100644 --- a/test/adapter_test.rb +++ b/test/adapter_test.rb @@ -55,6 +55,16 @@ def test_create_adapter_with_override assert_equal ActiveModelSerializers::Adapter::JsonApi, adapter.class end + def test_create_adapter_with_mime + json_context = ActiveModelSerializers::SerializationContext.new(format: :json) + adapter = ActiveModelSerializers::Adapter.create(@serializer, adapter: :mime, serialization_context: json_context) + assert_equal ActiveModelSerializers::Adapter::Json, adapter.class + + json_api_context = ActiveModelSerializers::SerializationContext.new(format: :json_api) + adapter = ActiveModelSerializers::Adapter.create(@serializer, adapter: :mime, serialization_context: json_api_context) + assert_equal ActiveModelSerializers::Adapter::JsonApi, adapter.class + end + def test_inflected_adapter_class_for_known_adapter ActiveSupport::Inflector.inflections(:en) { |inflect| inflect.acronym 'API' } klass = ActiveModelSerializers::Adapter.adapter_class(:json_api)