mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-22 22:06:50 +00:00
Introduce Adapter::Base
Breaking change: - Adapters now inherit Adapter::Base - 'Adapter' is now a module, no longer a class Why? - using a class as a namespace that you also inherit from is complicated and circular at time i.e. buggy (see https://github.com/rails-api/active_model_serializers/pull/1177) - The class methods on Adapter aren't necessarily related to the instance methods, they're more Adapter functions - named `Base` because it's a Rails-ism - It helps to isolate and highlight what the Adapter interface actually is
This commit is contained in:
parent
7cf0e93d03
commit
19de5f7722
14
CHANGELOG.md
14
CHANGELOG.md
@ -1,5 +1,15 @@
|
||||
### 0.10.0
|
||||
|
||||
Breaking changes:
|
||||
* Adapters now inherit Adapter::Base. 'Adapter' is now a module, no longer a class. [@bf4], #1138
|
||||
* using a class as a namespace that you also inherit from is complicated and circular at time i.e.
|
||||
buggy (see https://github.com/rails-api/active_model_serializers/pull/1177)
|
||||
* The class methods on Adapter aren't necessarily related to the instance methods, they're more
|
||||
Adapter functions
|
||||
* named `Base` because it's a Rails-ism
|
||||
* It helps to isolate and highlight what the Adapter interface actually is
|
||||
|
||||
Features:
|
||||
* adds adapters pattern
|
||||
* adds support for `meta` and `meta_key` [@kurko]
|
||||
* adds method to override association [@kurko]
|
||||
@ -12,3 +22,7 @@
|
||||
* adds FlattenJSON as default adapter [@joaomdmoura]
|
||||
* adds support for `pagination links` at top level of JsonApi adapter [@bacarini]
|
||||
* adds extended format for `include` option to JsonApi adapter [@beauby]
|
||||
|
||||
Fixes:
|
||||
|
||||
Misc:
|
||||
|
||||
@ -1,26 +1,30 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
UnknownAdapterError = Class.new(ArgumentError)
|
||||
ADAPTER_MAP = {}
|
||||
private_constant :ADAPTER_MAP if defined?(private_constant)
|
||||
require 'active_model/serializer/adapter/fragment_cache'
|
||||
require 'active_model/serializer/adapter/cached_serializer'
|
||||
|
||||
def self.create(resource, options = {})
|
||||
override = options.delete(:adapter)
|
||||
klass = override ? adapter_class(override) : ActiveModel::Serializer.adapter
|
||||
klass.new(resource, options)
|
||||
end
|
||||
class << self # All methods are class functions
|
||||
def new(*args)
|
||||
fail ArgumentError, 'Adapters inherit from Adapter::Base.' \
|
||||
"Adapter.new called with args: '#{args.inspect}', from" \
|
||||
"'caller[0]'."
|
||||
end
|
||||
|
||||
# @see ActiveModel::Serializer::Adapter.lookup
|
||||
def self.adapter_class(adapter)
|
||||
ActiveModel::Serializer::Adapter.lookup(adapter)
|
||||
end
|
||||
def create(resource, options = {})
|
||||
override = options.delete(:adapter)
|
||||
klass = override ? adapter_class(override) : ActiveModel::Serializer.adapter
|
||||
klass.new(resource, options)
|
||||
end
|
||||
|
||||
# @see ActiveModel::Serializer::Adapter.lookup
|
||||
def adapter_class(adapter)
|
||||
ActiveModel::Serializer::Adapter.lookup(adapter)
|
||||
end
|
||||
|
||||
# Only the Adapter class has these methods.
|
||||
# None of the sublasses have them.
|
||||
class << ActiveModel::Serializer::Adapter
|
||||
# @return Hash<adapter_name, adapter_class>
|
||||
def adapter_map
|
||||
ADAPTER_MAP
|
||||
@ -76,58 +80,8 @@ module ActiveModel
|
||||
private :find_by_name
|
||||
end
|
||||
|
||||
# Automatically register adapters when subclassing
|
||||
def self.inherited(subclass)
|
||||
ActiveModel::Serializer::Adapter.register(subclass)
|
||||
end
|
||||
|
||||
attr_reader :serializer, :instance_options
|
||||
|
||||
def initialize(serializer, options = {})
|
||||
@serializer = serializer
|
||||
@instance_options = options
|
||||
end
|
||||
|
||||
def serializable_hash(options = nil)
|
||||
raise NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.'
|
||||
end
|
||||
|
||||
def as_json(options = nil)
|
||||
hash = serializable_hash(options)
|
||||
include_meta(hash)
|
||||
hash
|
||||
end
|
||||
|
||||
def fragment_cache(*args)
|
||||
raise NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.'
|
||||
end
|
||||
|
||||
def cache_check(serializer)
|
||||
CachedSerializer.new(serializer).cache_check(self) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def meta
|
||||
serializer.meta if serializer.respond_to?(:meta)
|
||||
end
|
||||
|
||||
def meta_key
|
||||
serializer.meta_key || 'meta'.freeze
|
||||
end
|
||||
|
||||
def root
|
||||
serializer.json_key.to_sym if serializer.json_key
|
||||
end
|
||||
|
||||
def include_meta(json)
|
||||
json[meta_key] = meta if meta
|
||||
json
|
||||
end
|
||||
|
||||
# Gotta be at the bottom to use the code above it :(
|
||||
require 'active_model/serializer/adapter/base'
|
||||
require 'active_model/serializer/adapter/null'
|
||||
require 'active_model/serializer/adapter/attributes'
|
||||
require 'active_model/serializer/adapter/json'
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
class Attributes < Adapter
|
||||
module Adapter
|
||||
class Attributes < Base
|
||||
def serializable_hash(options = nil)
|
||||
options ||= {}
|
||||
if serializer.respond_to?(:each)
|
||||
|
||||
58
lib/active_model/serializer/adapter/base.rb
Normal file
58
lib/active_model/serializer/adapter/base.rb
Normal file
@ -0,0 +1,58 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
module Adapter
|
||||
class Base
|
||||
# Automatically register adapters when subclassing
|
||||
def self.inherited(subclass)
|
||||
ActiveModel::Serializer::Adapter.register(subclass)
|
||||
end
|
||||
|
||||
attr_reader :serializer, :instance_options
|
||||
|
||||
def initialize(serializer, options = {})
|
||||
@serializer = serializer
|
||||
@instance_options = options
|
||||
end
|
||||
|
||||
def serializable_hash(_options = nil)
|
||||
fail NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.'
|
||||
end
|
||||
|
||||
def as_json(options = nil)
|
||||
hash = serializable_hash(options)
|
||||
include_meta(hash)
|
||||
hash
|
||||
end
|
||||
|
||||
def fragment_cache(*_args)
|
||||
fail NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.'
|
||||
end
|
||||
|
||||
def cache_check(serializer)
|
||||
CachedSerializer.new(serializer).cache_check(self) do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def meta
|
||||
serializer.meta if serializer.respond_to?(:meta)
|
||||
end
|
||||
|
||||
def meta_key
|
||||
serializer.meta_key || 'meta'.freeze
|
||||
end
|
||||
|
||||
def root
|
||||
serializer.json_key.to_sym if serializer.json_key
|
||||
end
|
||||
|
||||
def include_meta(json)
|
||||
json[meta_key] = meta if meta
|
||||
json
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,6 +1,6 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class CachedSerializer
|
||||
def initialize(serializer)
|
||||
@cached_serializer = serializer
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class FragmentCache
|
||||
attr_reader :serializer
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
class Json < Adapter
|
||||
module Adapter
|
||||
class Json < Base
|
||||
extend ActiveSupport::Autoload
|
||||
autoload :FragmentCache
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class Json
|
||||
class FragmentCache
|
||||
def fragment_cache(cached_hash, non_cached_hash)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
class JsonApi < Adapter
|
||||
module Adapter
|
||||
class JsonApi < Base
|
||||
extend ActiveSupport::Autoload
|
||||
autoload :PaginationLinks
|
||||
autoload :FragmentCache
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class FragmentCache
|
||||
def fragment_cache(root, cached_hash, non_cached_hash)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
class JsonApi < Adapter
|
||||
module Adapter
|
||||
class JsonApi < Base
|
||||
class PaginationLinks
|
||||
FIRST_PAGE = 1
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
class Null < Adapter
|
||||
module Adapter
|
||||
class Null < Base
|
||||
def serializable_hash(options = nil)
|
||||
{}
|
||||
end
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
require 'test_helper'
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class FragmentCacheTest < Minitest::Test
|
||||
def setup
|
||||
@spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class Json
|
||||
class BelongsToTest < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class Json
|
||||
class Collection < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class Json
|
||||
class HasManyTestTest < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class BelongsToTest < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class CollectionTest < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class HasManyEmbedIdsTest < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
# Test 'has_many :assocs, serializer: AssocXSerializer'
|
||||
class HasManyExplicitSerializerTest < Minitest::Test
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class HasManyTest < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class HasOneTest < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApiTest < Minitest::Test
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
require 'test_helper'
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class LinkedTest < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -6,7 +6,7 @@ require 'kaminari/hooks'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class PaginationLinksTest < Minitest::Test
|
||||
URI = 'http://example.com'
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonApi
|
||||
class ResourceTypeConfigTest < Minitest::Test
|
||||
def setup
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class JsonTest < Minitest::Test
|
||||
def setup
|
||||
ActionController::Base.cache_store.clear
|
||||
|
||||
@ -2,7 +2,7 @@ require 'test_helper'
|
||||
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
class Adapter
|
||||
module Adapter
|
||||
class NullTest < Minitest::Test
|
||||
def setup
|
||||
profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
||||
|
||||
@ -6,7 +6,7 @@ module ActiveModel
|
||||
def setup
|
||||
profile = Profile.new
|
||||
@serializer = ProfileSerializer.new(profile)
|
||||
@adapter = ActiveModel::Serializer::Adapter.new(@serializer)
|
||||
@adapter = ActiveModel::Serializer::Adapter::Base.new(@serializer)
|
||||
end
|
||||
|
||||
def test_serializable_hash_is_abstract_method
|
||||
|
||||
@ -127,7 +127,7 @@ module ActiveModel
|
||||
def test_inherited_adapter_hooks_register_adapter
|
||||
Object.const_set(:MyAdapter, Class.new)
|
||||
my_adapter = MyAdapter
|
||||
ActiveModel::Serializer::Adapter.inherited(my_adapter)
|
||||
ActiveModel::Serializer::Adapter::Base.inherited(my_adapter)
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter
|
||||
ensure
|
||||
ActiveModel::Serializer::Adapter.adapter_map.delete('my_adapter'.freeze)
|
||||
@ -138,7 +138,7 @@ module ActiveModel
|
||||
Object.const_set(:MyNamespace, Module.new)
|
||||
MyNamespace.const_set(:MyAdapter, Class.new)
|
||||
my_adapter = MyNamespace::MyAdapter
|
||||
ActiveModel::Serializer::Adapter.inherited(my_adapter)
|
||||
ActiveModel::Serializer::Adapter::Base.inherited(my_adapter)
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(:'my_namespace/my_adapter'), my_adapter
|
||||
ensure
|
||||
ActiveModel::Serializer::Adapter.adapter_map.delete('my_namespace/my_adapter'.freeze)
|
||||
@ -151,8 +151,8 @@ module ActiveModel
|
||||
my_adapter = MyAdapter
|
||||
Object.const_set(:MySubclassedAdapter, Class.new(MyAdapter))
|
||||
my_subclassed_adapter = MySubclassedAdapter
|
||||
ActiveModel::Serializer::Adapter.inherited(my_adapter)
|
||||
ActiveModel::Serializer::Adapter.inherited(my_subclassed_adapter)
|
||||
ActiveModel::Serializer::Adapter::Base.inherited(my_adapter)
|
||||
ActiveModel::Serializer::Adapter::Base.inherited(my_subclassed_adapter)
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(:my_adapter), my_adapter
|
||||
assert_equal ActiveModel::Serializer::Adapter.lookup(:my_subclassed_adapter), my_subclassed_adapter
|
||||
ensure
|
||||
|
||||
Loading…
Reference in New Issue
Block a user