Skip to content

Commit 53d0e62

Browse files
committed
Add option to select adapter by the request header
1 parent 87c47f8 commit 53d0e62

File tree

4 files changed

+56
-0
lines changed

4 files changed

+56
-0
lines changed

lib/action_controller/serialization.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ def get_serializer(resource, options = {})
2525
"Please pass 'adapter: false' or see ActiveSupport::SerializableResource#serialize"
2626
options[:adapter] = false
2727
end
28+
29+
options[:adapter] ||= ActiveModel::Serializer::Adapter.by_request(request)
30+
2831
ActiveModel::SerializableResource.serialize(resource, options) do |serializable_resource|
2932
if serializable_resource.serializer?
3033
serializable_resource.serialization_scope ||= serialization_scope

lib/active_model/serializer.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,22 @@ def self.adapter
104104
adapter_class
105105
end
106106

107+
def self.custom_media_type_adapters=(media_type_adapters)
108+
config.custom_media_type_adapters ||= {}
109+
110+
unless media_type_adatets.is_a? Array
111+
media_types_adapters = [media_types_adapters]
112+
end
113+
114+
media_types_adapters.each do |media_type_adapter|
115+
config.custom_media_type_adapters.merge!(media_type_adapter)
116+
end
117+
end
118+
119+
def self.custom_media_type_adapters
120+
config.custom_media_type_adapters ||= {}
121+
end
122+
107123
def self.root_name
108124
name.demodulize.underscore.sub(/_serializer$/, '') if name
109125
end

lib/active_model/serializer/adapter.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ class Adapter
1111

1212
attr_reader :serializer
1313

14+
MEDIA_TYPE_ADAPTERS = {
15+
"application/vnd.api+json" => "json_api",
16+
"application/json" => "flatten_json"
17+
}
18+
1419
def initialize(serializer, options = {})
1520
@serializer = serializer
1621
@options = options
@@ -37,6 +42,13 @@ def self.adapter_class(adapter)
3742
"ActiveModel::Serializer::Adapter::#{adapter_name}".safe_constantize
3843
end
3944

45+
def self.by_request(request)
46+
return unless request && request.accept
47+
custom = ActiveModel::Serializer.custom_media_type_adapters
48+
media_type_adapters = MEDIA_TYPE_ADAPTERS.merge(custom)
49+
media_type_adapters[request.accept]
50+
end
51+
4052
def fragment_cache(*args)
4153
raise NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.'
4254
end

test/action_controller/adapter_selector_test.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ def render_skipping_adapter
1818
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
1919
render json: @profile, adapter: false
2020
end
21+
22+
def render_selecting_adapter_by_accept_header_field
23+
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
24+
render json: @profile
25+
end
2126
end
2227

2328
tests AdapterSelectorTestController
@@ -48,6 +53,26 @@ def test_render_skipping_adapter
4853
get :render_skipping_adapter
4954
assert_equal '{"attributes":{"name":"Name 1","description":"Description 1","comments":"Comments 1"}}', response.body
5055
end
56+
57+
def test_render_using_adapter_selected_by_accept_header_field
58+
request.headers['Accept'] = "application/vnd.api+json"
59+
60+
get :render_selecting_adapter_by_accept_header_field
61+
62+
expected = {
63+
data: {
64+
id: assigns(:profile).id.to_s,
65+
type: "profiles",
66+
attributes: {
67+
name: "Name 1",
68+
description: "Description 1",
69+
}
70+
}
71+
}
72+
73+
assert_equal expected.to_json, response.body
74+
end
75+
5176
end
5277
end
5378
end

0 commit comments

Comments
 (0)