Skip to content

Commit 50950d9

Browse files

File tree

6 files changed

+147
-0
lines changed

6 files changed

+147
-0
lines changed

lib/active_model/serializer.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
require 'active_model/serializer/fieldset'
1010
require 'active_model/serializer/lint'
1111
require 'active_model/serializer/links'
12+
require 'active_model/serializer/meta'
1213
require 'active_model/serializer/type'
1314

1415
# ActiveModel::Serializer is an abstract class that is
@@ -20,6 +21,7 @@ class Serializer
2021
include Attributes
2122
include Caching
2223
include Links
24+
include Meta
2325
include Type
2426
require 'active_model/serializer/adapter'
2527

lib/active_model/serializer/adapter/json_api.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class JsonApi < Base
88
autoload :Link
99
autoload :Association
1010
autoload :ResourceIdentifier
11+
autoload :Meta
1112
autoload :Deserialization
1213

1314
# TODO: if we like this abstraction and other API objects to it,
@@ -150,6 +151,9 @@ def resource_object_for(serializer)
150151
links = links_for(serializer)
151152
resource_object[:links] = links if links.any?
152153

154+
meta = meta_for(serializer)
155+
resource_object[:meta] = meta unless meta.nil?
156+
153157
resource_object
154158
end
155159

@@ -174,6 +178,10 @@ def links_for(serializer)
174178
def pagination_links_for(serializer, options)
175179
JsonApi::PaginationLinks.new(serializer.object, options[:serialization_context]).serializable_hash(options)
176180
end
181+
182+
def meta_for(serializer)
183+
Meta.new(serializer).as_json
184+
end
177185
end
178186
end
179187
end
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module ActiveModel
2+
class Serializer
3+
module Adapter
4+
class JsonApi
5+
class Meta
6+
def initialize(serializer)
7+
@object = serializer.object
8+
@scope = serializer.scope
9+
10+
# Use the return value of the block unless it is nil.
11+
if serializer._meta.respond_to?(:call)
12+
@value = instance_eval(&serializer._meta)
13+
else
14+
@value = serializer._meta
15+
end
16+
end
17+
18+
def as_json
19+
@value
20+
end
21+
22+
protected
23+
24+
attr_reader :object, :scope
25+
end
26+
end
27+
end
28+
end
29+
end

lib/active_model/serializer/meta.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module ActiveModel
2+
class Serializer
3+
module Meta
4+
extend ActiveSupport::Concern
5+
6+
included do
7+
with_options instance_writer: false, instance_reader: true do |serializer|
8+
serializer.class_attribute :_meta # @api private
9+
end
10+
11+
extend ActiveSupport::Autoload
12+
end
13+
14+
module ClassMethods
15+
# Set the JSON API meta attribute of a serializer.
16+
# @example
17+
# class AdminAuthorSerializer < ActiveModel::Serializer
18+
# meta { stuff: 'value' }
19+
# @example
20+
# meta do
21+
# { comment_count: object.comments.count }
22+
# end
23+
def meta(value = nil, &block)
24+
self._meta = block || value
25+
end
26+
end
27+
end
28+
end
29+
end
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
require 'test_helper'
2+
3+
module ActiveModel
4+
class Serializer
5+
module Adapter
6+
class JsonApi
7+
class ResourceMetaTest < Minitest::Test
8+
class MetaHashPostSerializer < ActiveModel::Serializer
9+
attributes :id
10+
meta stuff: 'value'
11+
end
12+
13+
class MetaBlockPostSerializer < ActiveModel::Serializer
14+
attributes :id
15+
meta do
16+
{ comments_count: object.comments.count }
17+
end
18+
end
19+
20+
def setup
21+
@post = Post.new(id: 1337, comments: [], author: nil)
22+
end
23+
24+
def test_meta_hash_object_resource
25+
hash = ActiveModel::SerializableResource.new(
26+
@post,
27+
serializer: MetaHashPostSerializer,
28+
adapter: :json_api
29+
).serializable_hash
30+
expected = {
31+
stuff: 'value'
32+
}
33+
assert_equal(expected, hash[:data][:meta])
34+
end
35+
36+
def test_meta_block_object_resource
37+
hash = ActiveModel::SerializableResource.new(
38+
@post,
39+
serializer: MetaBlockPostSerializer,
40+
adapter: :json_api
41+
).serializable_hash
42+
expected = {
43+
comments_count: @post.comments.count
44+
}
45+
assert_equal(expected, hash[:data][:meta])
46+
end
47+
48+
def test_meta_object_resource_in_array
49+
hash = ActiveModel::SerializableResource.new(
50+
[@post, @post],
51+
each_serializer: MetaBlockPostSerializer,
52+
adapter: :json_api
53+
).serializable_hash
54+
expected = {
55+
comments_count: @post.comments.count
56+
}
57+
assert_equal([expected, expected], hash[:data].map { |obj| obj[:meta] })
58+
end
59+
end
60+
end
61+
end
62+
end
63+
end

test/serializers/meta_test.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
module ActiveModel
44
class Serializer
55
class MetaTest < ActiveSupport::TestCase
6+
MetaBlogSerializer = Class.new(ActiveModel::Serializer)
7+
68
def setup
79
@blog = Blog.new(id: 1,
810
name: 'AMS Hints',
@@ -125,6 +127,20 @@ def test_meta_is_present_on_arrays_with_root
125127
}
126128
assert_equal(expected, actual)
127129
end
130+
131+
def test_meta_is_set_with_direct_attributes
132+
MetaBlogSerializer.meta stuff: 'value'
133+
blog_meta_serializer = MetaBlogSerializer.new(@blog)
134+
assert_equal(blog_meta_serializer.meta, stuff: 'value')
135+
end
136+
137+
def test_meta_is_set_with_block
138+
MetaBlogSerializer.meta do
139+
{ articles_count: object.articles.count }
140+
end
141+
blog_meta_serializer = MetaBlogSerializer.new(@blog)
142+
assert_equal(blog_meta_serializer.meta, articles_count: @blog.articles.count)
143+
end
128144
end
129145
end
130146
end

0 commit comments

Comments
 (0)