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

make a test override config.adapter
  • Loading branch information
ggordon committed Nov 13, 2014
1 parent 08fbba9 commit 5560b49
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)

This comment has been minimized.

Copy link
@jejacks0n

jejacks0n Nov 18, 2014

I like how this can now be overridden via the controller. This allows me to version my serializers based on controller module namespace or any other logic within the controller. Thanks for that.

@_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 =

This comment has been minimized.

Copy link
@jejacks0n

jejacks0n Nov 18, 2014

version 0.8.0 allows for providing default_serializer_options, I don't see this here.

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 5560b49

Please sign in to comment.