mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-22 22:06:50 +00:00
Add support for resource-level JSON API links.
This commit is contained in:
parent
827a623d16
commit
3804dcc238
@ -50,6 +50,9 @@ module ActiveModel
|
|||||||
self._attributes ||= []
|
self._attributes ||= []
|
||||||
class_attribute :_attributes_keys # @api private : maps attribute value to explict key name, @see Serializer#attribute
|
class_attribute :_attributes_keys # @api private : maps attribute value to explict key name, @see Serializer#attribute
|
||||||
self._attributes_keys ||= {}
|
self._attributes_keys ||= {}
|
||||||
|
class_attribute :_links # @api private : links definitions, @see Serializer#link
|
||||||
|
self._links ||= {}
|
||||||
|
|
||||||
serializer.class_attribute :_cache # @api private : the cache object
|
serializer.class_attribute :_cache # @api private : the cache object
|
||||||
serializer.class_attribute :_fragmented # @api private : @see ::fragmented
|
serializer.class_attribute :_fragmented # @api private : @see ::fragmented
|
||||||
serializer.class_attribute :_cache_key # @api private : when present, is first item in cache_key
|
serializer.class_attribute :_cache_key # @api private : when present, is first item in cache_key
|
||||||
@ -72,6 +75,7 @@ module ActiveModel
|
|||||||
caller_line = caller.first
|
caller_line = caller.first
|
||||||
base._attributes = _attributes.dup
|
base._attributes = _attributes.dup
|
||||||
base._attributes_keys = _attributes_keys.dup
|
base._attributes_keys = _attributes_keys.dup
|
||||||
|
base._links = _links.dup
|
||||||
base._cache_digest = digest_caller_file(caller_line)
|
base._cache_digest = digest_caller_file(caller_line)
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
@ -83,6 +87,10 @@ module ActiveModel
|
|||||||
self._type = type
|
self._type = type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.link(name, value = nil, &block)
|
||||||
|
_links[name] = block || value
|
||||||
|
end
|
||||||
|
|
||||||
# @example
|
# @example
|
||||||
# class AdminAuthorSerializer < ActiveModel::Serializer
|
# class AdminAuthorSerializer < ActiveModel::Serializer
|
||||||
# attributes :id, :name, :recent_edits
|
# attributes :id, :name, :recent_edits
|
||||||
@ -249,6 +257,12 @@ module ActiveModel
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @api private
|
||||||
|
# Used by JsonApi adapter to build resource links.
|
||||||
|
def links
|
||||||
|
self.class._links
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
attr_accessor :instance_options
|
attr_accessor :instance_options
|
||||||
|
|||||||
@ -5,6 +5,7 @@ module ActiveModel
|
|||||||
extend ActiveSupport::Autoload
|
extend ActiveSupport::Autoload
|
||||||
autoload :PaginationLinks
|
autoload :PaginationLinks
|
||||||
autoload :FragmentCache
|
autoload :FragmentCache
|
||||||
|
autoload :Link
|
||||||
|
|
||||||
# TODO: if we like this abstraction and other API objects to it,
|
# TODO: if we like this abstraction and other API objects to it,
|
||||||
# then extract to its own file and require it.
|
# then extract to its own file and require it.
|
||||||
@ -94,7 +95,7 @@ module ActiveModel
|
|||||||
|
|
||||||
if serializer.paginated?
|
if serializer.paginated?
|
||||||
hash[:links] ||= {}
|
hash[:links] ||= {}
|
||||||
hash[:links].update(links_for(serializer, options))
|
hash[:links].update(pagination_links_for(serializer, options))
|
||||||
end
|
end
|
||||||
|
|
||||||
hash
|
hash
|
||||||
@ -136,12 +137,21 @@ module ActiveModel
|
|||||||
{ id: id.to_s, type: type }
|
{ id: id.to_s, type: type }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def attributes_for(serializer, fields)
|
||||||
|
serializer.attributes(fields).except(:id)
|
||||||
|
end
|
||||||
|
|
||||||
def resource_object_for(serializer)
|
def resource_object_for(serializer)
|
||||||
cache_check(serializer) do
|
cache_check(serializer) do
|
||||||
resource_object = resource_identifier_for(serializer)
|
resource_object = resource_identifier_for(serializer)
|
||||||
|
|
||||||
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
requested_fields = fieldset && fieldset.fields_for(resource_object[:type])
|
||||||
attributes = serializer.attributes(requested_fields).except(:id)
|
attributes = attributes_for(serializer, requested_fields)
|
||||||
resource_object[:attributes] = attributes if attributes.any?
|
resource_object[:attributes] = attributes if attributes.any?
|
||||||
|
|
||||||
|
links = links_for(serializer)
|
||||||
|
resource_object[:links] = links if links.any?
|
||||||
|
|
||||||
resource_object
|
resource_object
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -204,7 +214,21 @@ module ActiveModel
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def links_for(serializer, options)
|
def links_for(serializer)
|
||||||
|
serializer.links.each_with_object({}) do |(name, value), hash|
|
||||||
|
hash[name] =
|
||||||
|
if value.respond_to?(:call)
|
||||||
|
link = Link.new(serializer)
|
||||||
|
link.instance_eval(&value)
|
||||||
|
|
||||||
|
link.to_hash
|
||||||
|
else
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pagination_links_for(serializer, options)
|
||||||
JsonApi::PaginationLinks.new(serializer.object, options[:context]).serializable_hash(options)
|
JsonApi::PaginationLinks.new(serializer.object, options[:context]).serializable_hash(options)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
34
lib/active_model/serializer/adapter/json_api/link.rb
Normal file
34
lib/active_model/serializer/adapter/json_api/link.rb
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
module ActiveModel
|
||||||
|
class Serializer
|
||||||
|
module Adapter
|
||||||
|
class JsonApi
|
||||||
|
class Link
|
||||||
|
def initialize(serializer)
|
||||||
|
@object = serializer.object
|
||||||
|
@scope = serializer.scope
|
||||||
|
end
|
||||||
|
|
||||||
|
def href(value)
|
||||||
|
self._href = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def meta(value)
|
||||||
|
self._meta = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_hash
|
||||||
|
hash = { href: _href }
|
||||||
|
hash.merge!(meta: _meta) if _meta
|
||||||
|
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
attr_accessor :_href, :_meta
|
||||||
|
attr_reader :object, :scope
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -5,8 +5,19 @@ module ActiveModel
|
|||||||
module Adapter
|
module Adapter
|
||||||
class JsonApi
|
class JsonApi
|
||||||
class LinksTest < Minitest::Test
|
class LinksTest < Minitest::Test
|
||||||
|
LinkAuthor = Class.new(::Model)
|
||||||
|
class LinkAuthorSerializer < ActiveModel::Serializer
|
||||||
|
link :self do
|
||||||
|
href "//example.com/link_author/#{object.id}"
|
||||||
|
meta stuff: 'value'
|
||||||
|
end
|
||||||
|
|
||||||
|
link :other, '//example.com/resource'
|
||||||
|
end
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@post = Post.new(id: 1337, comments: [], author: nil)
|
@post = Post.new(id: 1337, comments: [], author: nil)
|
||||||
|
@author = LinkAuthor.new(id: 1337)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_toplevel_links
|
def test_toplevel_links
|
||||||
@ -15,16 +26,36 @@ module ActiveModel
|
|||||||
adapter: :json_api,
|
adapter: :json_api,
|
||||||
links: {
|
links: {
|
||||||
self: {
|
self: {
|
||||||
href: '//posts'
|
href: '//example.com/posts',
|
||||||
|
meta: {
|
||||||
|
stuff: 'value'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).serializable_hash
|
}).serializable_hash
|
||||||
expected = {
|
expected = {
|
||||||
self: {
|
self: {
|
||||||
href: '//posts'
|
href: '//example.com/posts',
|
||||||
|
meta: {
|
||||||
|
stuff: 'value'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert_equal(expected, hash[:links])
|
assert_equal(expected, hash[:links])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_resource_links
|
||||||
|
hash = serializable(@author, adapter: :json_api).serializable_hash
|
||||||
|
expected = {
|
||||||
|
self: {
|
||||||
|
href: '//example.com/link_author/1337',
|
||||||
|
meta: {
|
||||||
|
stuff: 'value'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
other: '//example.com/resource'
|
||||||
|
}
|
||||||
|
assert_equal(expected, hash[:data][:links])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user