Skip to content

Commit c84430c

Browse files
committed
Support serializer and each_serializer in render json
1 parent 95d1220 commit c84430c

File tree

5 files changed

+100
-7
lines changed

5 files changed

+100
-7
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,22 @@ member when the resource names are included in the `include` option.
9494
render @posts, include: 'authors,comments'
9595
```
9696

97+
### Specify a serializer
98+
99+
If you wish to use a serializer other than the default, you can explicitly pass it to the renderer.
100+
101+
#### 1. For a resource:
102+
103+
```ruby
104+
render json: @post, serializer: PostPreviewSerializer
105+
```
106+
107+
#### 2. For an array resource:
108+
109+
```ruby
110+
render json: @posts, serializer: PaginatedSerializer, each_serializer: PostPreviewSerializer
111+
```
112+
97113
## Installation
98114

99115
Add this line to your application's Gemfile:

lib/action_controller/serialization.rb

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,25 @@ module Serialization
88

99
ADAPTER_OPTION_KEYS = [:include, :root]
1010

11+
def get_serializer(resource, options)
12+
@_serializer ||= if (serializer = options.delete :serializer)
13+
options[:serializer] = options.delete :each_serializer
14+
serializer
15+
else
16+
ActiveModel::Serializer.serializer_for(resource)
17+
end
18+
end
19+
1120
[:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
1221
define_method renderer_method do |resource, options|
13-
serializer = ActiveModel::Serializer.serializer_for(resource)
1422

15-
if serializer
16-
adapter_opts, serializer_opts =
17-
options.partition { |k, _| ADAPTER_OPTION_KEYS.include? k }
23+
adapter_opts, serializer_opts =
24+
options.partition { |k, _| ADAPTER_OPTION_KEYS.include? k }.map { |h| Hash[h] }
25+
26+
if (serializer = get_serializer(resource, serializer_opts))
1827
# omg hax
19-
object = serializer.new(resource, Hash[serializer_opts])
20-
adapter = ActiveModel::Serializer.adapter.new(object, Hash[adapter_opts])
28+
object = serializer.new(resource, serializer_opts)
29+
adapter = ActiveModel::Serializer.adapter.new(object, adapter_opts)
2130
super(adapter, options)
2231
else
2332
super(resource, options)

lib/active_model/serializer/array_serializer.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ class ArraySerializer
66

77
def initialize(objects, options = {})
88
@objects = objects.map do |object|
9-
serializer_class = ActiveModel::Serializer.serializer_for(object)
9+
serializer_class = options.fetch(
10+
:serializer,
11+
ActiveModel::Serializer.serializer_for(object)
12+
)
1013
serializer_class.new(object)
1114
end
1215
end
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
require 'test_helper'
2+
3+
module ActionController
4+
module Serialization
5+
class ExplicitSerializerTest < ActionController::TestCase
6+
class MyController < ActionController::Base
7+
def render_using_explicit_serializer
8+
@profile = Profile.new(name: 'Name 1',
9+
description: 'Description 1',
10+
comments: 'Comments 1')
11+
render json: @profile, serializer: ProfilePreviewSerializer
12+
end
13+
14+
def render_array_using_explicit_serializer
15+
array = [
16+
Profile.new(name: 'Name 1',
17+
description: 'Description 1',
18+
comments: 'Comments 1'),
19+
Profile.new(name: 'Name 2',
20+
description: 'Description 2',
21+
comments: 'Comments 2')
22+
]
23+
render json: array,
24+
serializer: PaginatedSerializer,
25+
each_serializer: ProfilePreviewSerializer
26+
end
27+
end
28+
29+
tests MyController
30+
31+
def test_render_using_explicit_serializer
32+
get :render_using_explicit_serializer
33+
34+
assert_equal 'application/json', @response.content_type
35+
assert_equal '{"name":"Name 1"}', @response.body
36+
end
37+
38+
def test_render_array_using_explicit_serializer
39+
get :render_array_using_explicit_serializer
40+
assert_equal 'application/json', @response.content_type
41+
42+
expected = {
43+
'paginated' => [
44+
{ 'name' => 'Name 1' },
45+
{ 'name' => 'Name 2' }
46+
]
47+
}
48+
49+
assert_equal expected.to_json, @response.body
50+
end
51+
end
52+
end
53+
end

test/fixtures/poro.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ class ProfileSerializer < ActiveModel::Serializer
3535
urls :posts, :comments
3636
end
3737

38+
class ProfilePreviewSerializer < ActiveModel::Serializer
39+
attributes :name
40+
41+
urls :posts, :comments
42+
end
43+
3844
Post = Class.new(Model)
3945
Comment = Class.new(Model)
4046
Author = Class.new(Model)
@@ -67,3 +73,9 @@ class ProfileSerializer < ActiveModel::Serializer
6773
belongs_to :writer
6874
has_many :articles
6975
end
76+
77+
PaginatedSerializer = Class.new(ActiveModel::Serializer::ArraySerializer) do
78+
def json_key
79+
'paginated'
80+
end
81+
end

0 commit comments

Comments
 (0)