Skip to content

Commit

Permalink
Fix rails-api#1759, Grape integration, adds serialization_context (#4)
Browse files Browse the repository at this point in the history
* Fix rails-api#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.
  • Loading branch information
onomated authored and bf4 committed Jun 9, 2016
1 parent 16fe761 commit 7b90b90
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Features:
Fixes:
- [#1754](https://github.com/rails-api/active_model_serializers/pull/1754) Fixes #1759, Grape integration, improves serialization_context
missing error message on pagination. Document overriding CollectionSerializer#paginated?. (@bf4)
- [#1754](https://github.com/rails-api/active_model_serializers/pull/1754) Fixes #1759, Grape integration, moved serialization_context
creation to Grape formatter, so resource serialization works without explicit calls to the `render` helper method. Added Grape collection tests. (@onomated)
- [#1710](https://github.com/rails-api/active_model_serializers/pull/1710) Prevent association loading when `include_data` option
is set to `false`. (@groyoh)
- [#1747](https://github.com/rails-api/active_model_serializers/pull/1747) Improve jsonapi mime type registration for Rails 5 (@remear)
Expand Down
21 changes: 19 additions & 2 deletions lib/grape/formatters/active_model_serializers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,31 @@
#
# Serializer options can be passed as a hash from your Grape endpoint using env[:active_model_serializer_options],
# or better yet user the render helper in Grape::Helpers::ActiveModelSerializers

require 'active_model_serializers/serialization_context'

module Grape
module Formatters
module ActiveModelSerializers
def self.call(resource, env)
serializer_options = {}
serializer_options.merge!(env[:active_model_serializer_options]) if env[:active_model_serializer_options]
serializer_options = build_serializer_options(env)
::ActiveModelSerializers::SerializableResource.new(resource, serializer_options).to_json
end

def self.build_serializer_options(env)
ams_options = env[:active_model_serializer_options] || {}

# Add serialization context
ams_options.fetch(:serialization_context) do
request = env['grape.request']
ams_options[:serialization_context] = ::ActiveModelSerializers::SerializationContext.new(
request_url: request.url[/\A[^?]+/],
query_parameters: request.params
)
end

ams_options
end
end
end
end
8 changes: 0 additions & 8 deletions lib/grape/helpers/active_model_serializers.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Helpers can be included in your Grape endpoint as: helpers Grape::Helpers::ActiveModelSerializers

require 'active_model_serializers/serialization_context'

module Grape
module Helpers
module ActiveModelSerializers
Expand All @@ -11,12 +9,6 @@ module ActiveModelSerializers
#
# Example: To include pagination meta data: render(posts, meta: { page: posts.page, total_pages: posts.total_pages })
def render(resource, active_model_serializer_options = {})
active_model_serializer_options.fetch(:serialization_context) do
active_model_serializer_options[:serialization_context] = ::ActiveModelSerializers::SerializationContext.new(
original_url: request.url[/\A[^?]+/],
query_parameters: request.params
)
end
env[:active_model_serializer_options] = active_model_serializer_options
resource
end
Expand Down
95 changes: 93 additions & 2 deletions test/grape_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
require 'test_helper'
require 'grape'
require 'grape/active_model_serializers'
require 'kaminari'
require 'kaminari/hooks'
::Kaminari::Hooks.init

class ActiveModelSerializers::GrapeTest < ActiveSupport::TestCase
include Rack::Test::Methods
Expand All @@ -21,6 +24,30 @@ def self.all
ARModels::Post.all
end
end

def self.reset_all
ARModels::Post.delete_all
@all = nil
end

def self.collection_per
2
end

def self.collection
@collection ||=
begin
Kaminari.paginate_array(
[
Profile.new(id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
Profile.new(id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2'),
Profile.new(id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3'),
Profile.new(id: 4, name: 'Name 4', description: 'Description 4', comments: 'Comments 4'),
Profile.new(id: 5, name: 'Name 5', description: 'Description 5', comments: 'Comments 5')
]
).page(1).per(collection_per)
end
end
end

class GrapeTest < Grape::API
Expand All @@ -41,11 +68,28 @@ class GrapeTest < Grape::API
posts = Models.all
render posts, adapter: :json_api
end

get '/render_collection_with_json_api' do
posts = Models.collection
render posts, adapter: :json_api
end

get '/render_with_implicit_formatter' do
Models.model1
end

get '/render_array_with_implicit_formatter' do
Models.all
end

get '/render_collection_with_implicit_formatter' do
Models.collection
end
end
end

def app
GrapeTest.new
Grape::Middleware::Globals.new(GrapeTest.new)
end

def test_formatter_returns_json
Expand Down Expand Up @@ -77,6 +121,53 @@ def test_formatter_handles_arrays
assert last_response.ok?
assert_equal serializable_resource.to_json, last_response.body
ensure
ARModels::Post.delete_all
Models.reset_all
end

def test_formatter_handles_collections
get '/grape/render_collection_with_json_api'
assert last_response.ok?

representation = JSON.parse(last_response.body)
assert representation.include?('data')
assert representation['data'].count == Models.collection_per
assert representation.include?('links')
assert representation['links'].count > 0
end

def test_implicit_formatter
ActiveModel::Serializer.config.adapter = :json_api
get '/grape/render_with_implicit_formatter'

post = Models.model1
serializable_resource = serializable(post, adapter: :json_api)

assert last_response.ok?
assert_equal serializable_resource.to_json, last_response.body
end

def test_implicit_formatter_handles_arrays
ActiveModel::Serializer.config.adapter = :json_api
get '/grape/render_array_with_implicit_formatter'

posts = Models.all
serializable_resource = serializable(posts, adapter: :json_api)

assert last_response.ok?
assert_equal serializable_resource.to_json, last_response.body
ensure
Models.reset_all
end

def test_implicit_formatter_handles_collections
ActiveModel::Serializer.config.adapter = :json_api
get '/grape/render_collection_with_implicit_formatter'
assert last_response.ok?

representation = JSON.parse(last_response.body)
assert representation.include?('data')
assert representation['data'].count == Models.collection_per
assert representation.include?('links')
assert representation['links'].count > 0
end
end

0 comments on commit 7b90b90

Please sign in to comment.