Skip to content

Commit

Permalink
Merge pull request #718 from ggordon/adapter_override
Browse files Browse the repository at this point in the history
Allow overriding the adapter with render option
  • Loading branch information
kurko committed Nov 13, 2014
2 parents 08fbba9 + 5560b49 commit c53f1da
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 50 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 @@ -90,8 +90,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
6 changes: 1 addition & 5 deletions test/action_controller/serialization_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,9 @@ def render_using_default_adapter_root
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 c53f1da

Please sign in to comment.