Skip to content

Commit 5804922

Browse files
onomatedbf4
authored andcommitted
Fix #1759, Grape integration, adds serialization_context (#4)
* Fix #1759, Grape integration, adds serialization_context - `serialization_context` is added in grape formatter so grape continues to render models without an explicit call to the `render` helper method - Made it straightforward for subclasses to add other serializer options (such as `serialization_scope`). * Updated Grape tests to include: - paginated collections - implicit Grape serializer (i.e. without explicit invocation of `render` helper method) * Update Changelog with fixes.
1 parent a7296e8 commit 5804922

File tree

4 files changed

+114
-12
lines changed

4 files changed

+114
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ Features:
1111
Fixes:
1212
- [#1754](https://github.com/rails-api/active_model_serializers/pull/1754) Fixes #1759, Grape integration, improves serialization_context
1313
missing error message on pagination. Document overriding CollectionSerializer#paginated?. (@bf4)
14+
Moved serialization_context creation to Grape formatter, so resource serialization works without explicit calls to the `render` helper method.
15+
Added Grape collection tests. (@onomated)
1416
- [#1287](https://github.com/rails-api/active_model_serializers/pull/1287) Pass `fields` options from adapter to serializer. (@vasilakisfil)
1517
- [#1710](https://github.com/rails-api/active_model_serializers/pull/1710) Prevent association loading when `include_data` option
1618
is set to `false`. (@groyoh)

lib/grape/formatters/active_model_serializers.rb

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,31 @@
22
#
33
# Serializer options can be passed as a hash from your Grape endpoint using env[:active_model_serializer_options],
44
# or better yet user the render helper in Grape::Helpers::ActiveModelSerializers
5+
6+
require 'active_model_serializers/serialization_context'
7+
58
module Grape
69
module Formatters
710
module ActiveModelSerializers
811
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)
1113
::ActiveModelSerializers::SerializableResource.new(resource, serializer_options).to_json
1214
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
1330
end
1431
end
1532
end

lib/grape/helpers/active_model_serializers.rb

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Helpers can be included in your Grape endpoint as: helpers Grape::Helpers::ActiveModelSerializers
22

3-
require 'active_model_serializers/serialization_context'
4-
53
module Grape
64
module Helpers
75
module ActiveModelSerializers
@@ -11,12 +9,6 @@ module ActiveModelSerializers
119
#
1210
# Example: To include pagination meta data: render(posts, meta: { page: posts.page, total_pages: posts.total_pages })
1311
def render(resource, active_model_serializer_options = {})
14-
active_model_serializer_options.fetch(:serialization_context) do
15-
active_model_serializer_options[:serialization_context] = ::ActiveModelSerializers::SerializationContext.new(
16-
original_url: request.url[/\A[^?]+/],
17-
query_parameters: request.params
18-
)
19-
end
2012
env[:active_model_serializer_options] = active_model_serializer_options
2113
resource
2214
end

test/grape_test.rb

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
require 'test_helper'
22
require 'grape'
33
require 'grape/active_model_serializers'
4+
require 'kaminari'
5+
require 'kaminari/hooks'
6+
::Kaminari::Hooks.init
47

58
class ActiveModelSerializers::GrapeTest < ActiveSupport::TestCase
69
include Rack::Test::Methods
@@ -21,6 +24,30 @@ def self.all
2124
ARModels::Post.all
2225
end
2326
end
27+
28+
def self.reset_all
29+
ARModels::Post.delete_all
30+
@all = nil
31+
end
32+
33+
def self.collection_per
34+
2
35+
end
36+
37+
def self.collection
38+
@collection ||=
39+
begin
40+
Kaminari.paginate_array(
41+
[
42+
Profile.new(id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
43+
Profile.new(id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2'),
44+
Profile.new(id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3'),
45+
Profile.new(id: 4, name: 'Name 4', description: 'Description 4', comments: 'Comments 4'),
46+
Profile.new(id: 5, name: 'Name 5', description: 'Description 5', comments: 'Comments 5')
47+
]
48+
).page(1).per(collection_per)
49+
end
50+
end
2451
end
2552

2653
class GrapeTest < Grape::API
@@ -41,11 +68,28 @@ class GrapeTest < Grape::API
4168
posts = Models.all
4269
render posts, adapter: :json_api
4370
end
71+
72+
get '/render_collection_with_json_api' do
73+
posts = Models.collection
74+
render posts, adapter: :json_api
75+
end
76+
77+
get '/render_with_implicit_formatter' do
78+
Models.model1
79+
end
80+
81+
get '/render_array_with_implicit_formatter' do
82+
Models.all
83+
end
84+
85+
get '/render_collection_with_implicit_formatter' do
86+
Models.collection
87+
end
4488
end
4589
end
4690

4791
def app
48-
GrapeTest.new
92+
Grape::Middleware::Globals.new(GrapeTest.new)
4993
end
5094

5195
def test_formatter_returns_json
@@ -77,6 +121,53 @@ def test_formatter_handles_arrays
77121
assert last_response.ok?
78122
assert_equal serializable_resource.to_json, last_response.body
79123
ensure
80-
ARModels::Post.delete_all
124+
Models.reset_all
125+
end
126+
127+
def test_formatter_handles_collections
128+
get '/grape/render_collection_with_json_api'
129+
assert last_response.ok?
130+
131+
representation = JSON.parse(last_response.body)
132+
assert representation.include?('data')
133+
assert representation['data'].count == Models.collection_per
134+
assert representation.include?('links')
135+
assert representation['links'].count > 0
136+
end
137+
138+
def test_implicit_formatter
139+
ActiveModel::Serializer.config.adapter = :json_api
140+
get '/grape/render_with_implicit_formatter'
141+
142+
post = Models.model1
143+
serializable_resource = serializable(post, adapter: :json_api)
144+
145+
assert last_response.ok?
146+
assert_equal serializable_resource.to_json, last_response.body
147+
end
148+
149+
def test_implicit_formatter_handles_arrays
150+
ActiveModel::Serializer.config.adapter = :json_api
151+
get '/grape/render_array_with_implicit_formatter'
152+
153+
posts = Models.all
154+
serializable_resource = serializable(posts, adapter: :json_api)
155+
156+
assert last_response.ok?
157+
assert_equal serializable_resource.to_json, last_response.body
158+
ensure
159+
Models.reset_all
160+
end
161+
162+
def test_implicit_formatter_handles_collections
163+
ActiveModel::Serializer.config.adapter = :json_api
164+
get '/grape/render_collection_with_implicit_formatter'
165+
assert last_response.ok?
166+
167+
representation = JSON.parse(last_response.body)
168+
assert representation.include?('data')
169+
assert representation['data'].count == Models.collection_per
170+
assert representation.include?('links')
171+
assert representation['links'].count > 0
81172
end
82173
end

0 commit comments

Comments
 (0)