Skip to content

Commit

Permalink
Allow overriding the adapter with render option
Browse files Browse the repository at this point in the history
Make it easy to use multiple adapters in an app.

use "adapter: false" to not use ams
  • Loading branch information
ggordon committed Nov 13, 2014
1 parent ac37570 commit 768224c
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 55 deletions.
23 changes: 13 additions & 10 deletions lib/action_controller/serialization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,32 @@ module Serialization

include ActionController::Renderers

ADAPTER_OPTION_KEYS = [:include, :root]
ADAPTER_OPTION_KEYS = [:include, :root, :adapter]

def get_serializer(resource, options)
@_serializer ||= options.delete(:serializer)
def get_serializer(resource)
@_serializer ||= @_serializer_opts.delete(:serializer)
@_serializer ||= ActiveModel::Serializer.serializer_for(resource)

if options.key?(:each_serializer)
options[:serializer] = options.delete(:each_serializer)
if @_serializer_opts.key?(:each_serializer)
@_serializer_opts[:serializer] = @_serializer_opts.delete(:each_serializer)
end

@_serializer
end

def use_adapter?
!(@_adapter_opts.key?(:adapter) && !@_adapter_opts[:adapter])
end

[:_render_option_json, :_render_with_renderer_json].each do |renderer_method|
define_method renderer_method do |resource, options|

adapter_opts, serializer_opts =
@_adapter_opts, @_serializer_opts =
options.partition { |k, _| ADAPTER_OPTION_KEYS.include? k }.map { |h| Hash[h] }

if (serializer = get_serializer(resource, serializer_opts))
if use_adapter? && (serializer = get_serializer(resource))
# omg hax
object = serializer.new(resource, serializer_opts)
adapter = ActiveModel::Serializer.adapter.new(object, adapter_opts)
object = serializer.new(resource, @_serializer_opts)
adapter = ActiveModel::Serializer::Adapter.create(object, @_adapter_opts)
super(adapter, options)
else
super(resource, options)
Expand Down
3 changes: 1 addition & 2 deletions lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ def self.serializer_for(resource)
def self.adapter
adapter_class = case config.adapter
when Symbol
class_name = "ActiveModel::Serializer::Adapter::#{config.adapter.to_s.classify}"
class_name.safe_constantize
ActiveModel::Serializer::Adapter.adapter_class(config.adapter)
when Class
config.adapter
end
Expand Down
10 changes: 10 additions & 0 deletions lib/active_model/serializer/adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ def serializable_hash(options = {})
def as_json(options = {})
serializable_hash(options)
end

def self.create(resource, options = {})
override = options.delete(:adapter)
klass = override ? adapter_class(override) : ActiveModel::Serializer.adapter
klass.new(resource, options)
end

def self.adapter_class(adapter)
"ActiveModel::Serializer::Adapter::#{adapter.to_s.classify}".safe_constantize
end
end
end
end
41 changes: 41 additions & 0 deletions test/action_controller/adapter_selector_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'test_helper'

module ActionController
module Serialization
class AdapterSelectorTest < ActionController::TestCase
class MyController < ActionController::Base
def render_using_default_adapter
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
render json: @profile
end

def render_using_adapter_override
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
render json: @profile, adapter: :json_api
end

def render_skipping_adapter
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
render json: @profile, adapter: false
end
end

tests MyController

def test_render_using_default_adapter
get :render_using_default_adapter
assert_equal '{"name":"Name 1","description":"Description 1"}', response.body
end

def test_render_using_adapter_override
get :render_using_adapter_override
assert_equal '{"profiles":{"name":"Name 1","description":"Description 1"}}', response.body
end

def test_render_skipping_adapter
get :render_skipping_adapter
assert_equal '{"attributes":{"name":"Name 1","description":"Description 1","comments":"Comments 1"}}', response.body
end
end
end
end
44 changes: 12 additions & 32 deletions test/action_controller/json_api_linked_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,54 +28,34 @@ def setup_post
@second_comment.author = nil
end

def with_json_api_adapter
old_adapter = ActiveModel::Serializer.config.adapter
ActiveModel::Serializer.config.adapter = :json_api
yield
ensure
ActiveModel::Serializer.config.adapter = old_adapter
end

def render_resource_without_include
with_json_api_adapter do
setup_post
render json: @post
end
setup_post
render json: @post, adapter: :json_api
end

def render_resource_with_include
with_json_api_adapter do
setup_post
render json: @post, include: 'author'
end
setup_post
render json: @post, include: 'author', adapter: :json_api
end

def render_resource_with_nested_include
with_json_api_adapter do
setup_post
render json: @post, include: 'comments.author'
end
setup_post
render json: @post, include: 'comments.author', adapter: :json_api
end

def render_resource_with_nested_has_many_include
with_json_api_adapter do
setup_post
render json: @post, include: 'author,author.roles'
end
setup_post
render json: @post, include: 'author,author.roles', adapter: :json_api
end

def render_collection_without_include
with_json_api_adapter do
setup_post
render json: [@post]
end
setup_post
render json: [@post], adapter: :json_api
end

def render_collection_with_include
with_json_api_adapter do
setup_post
render json: [@post], include: 'author,comments'
end
setup_post
render json: [@post], include: 'author,comments', adapter: :json_api
end
end

Expand Down
12 changes: 2 additions & 10 deletions test/action_controller/serialization_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,15 @@ def render_using_custom_root
end

def render_using_default_adapter_root
old_adapter = ActiveModel::Serializer.config.adapter
# JSON-API adapter sets root by default
ActiveModel::Serializer.config.adapter = ActiveModel::Serializer::Adapter::JsonApi
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
render json: @profile
ensure
ActiveModel::Serializer.config.adapter = old_adapter
render json: @profile, adapter: :json_api
end

def render_using_custom_root_in_adapter_with_a_default
old_adapter = ActiveModel::Serializer.config.adapter
# JSON-API adapter sets root by default
ActiveModel::Serializer.config.adapter = ActiveModel::Serializer::Adapter::JsonApi
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
render json: @profile, root: "profile"
ensure
ActiveModel::Serializer.config.adapter = old_adapter
render json: @profile, root: "profile", adapter: :json_api
end

def render_array_using_implicit_serializer
Expand Down
20 changes: 20 additions & 0 deletions test/adapter_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@ def test_serializable_hash_is_abstract_method
def test_serializer
assert_equal @serializer, @adapter.serializer
end

def test_adapter_class_for_known_adapter
klass = ActiveModel::Serializer::Adapter.adapter_class(:json_api)
assert_equal ActiveModel::Serializer::Adapter::JsonApi, klass
end

def test_adapter_class_for_unknown_adapter
klass = ActiveModel::Serializer::Adapter.adapter_class(:json_simple)
assert_nil klass
end

def test_create_adapter
adapter = ActiveModel::Serializer::Adapter.create(@serializer)
assert_equal ActiveModel::Serializer::Adapter::Json, adapter.class
end

def test_create_adapter_with_override
adapter = ActiveModel::Serializer::Adapter.create(@serializer, { adapter: :json_api})
assert_equal ActiveModel::Serializer::Adapter::JsonApi, adapter.class
end
end
end
end
2 changes: 1 addition & 1 deletion test/serializers/configuration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def test_array_serializer
assert_equal ActiveModel::Serializer::ArraySerializer, ActiveModel::Serializer.config.array_serializer
end

def test_adapter
def test_default_adapter
assert_equal :json, ActiveModel::Serializer.config.adapter
end
end
Expand Down

0 comments on commit 768224c

Please sign in to comment.