active_model_serializers 0.10.2 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +8 -1
- data/CHANGELOG.md +45 -3
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -1
- data/README.md +5 -2
- data/active_model_serializers.gemspec +2 -2
- data/docs/ARCHITECTURE.md +6 -7
- data/docs/README.md +2 -0
- data/docs/general/caching.md +7 -1
- data/docs/general/configuration_options.md +64 -0
- data/docs/general/rendering.md +35 -1
- data/docs/general/serializers.md +35 -5
- data/docs/howto/add_pagination_links.md +2 -2
- data/docs/howto/add_relationship_links.md +137 -0
- data/docs/howto/add_root_key.md +4 -0
- data/docs/howto/grape_integration.md +42 -0
- data/docs/howto/outside_controller_use.md +9 -2
- data/docs/howto/passing_arbitrary_options.md +2 -2
- data/docs/howto/test.md +2 -0
- data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
- data/docs/integrations/ember-and-json-api.md +41 -24
- data/lib/action_controller/serialization.rb +9 -0
- data/lib/active_model/serializer.rb +19 -22
- data/lib/active_model/serializer/association.rb +19 -4
- data/lib/active_model/serializer/collection_serializer.rb +8 -5
- data/lib/active_model/serializer/{associations.rb → concerns/associations.rb} +8 -5
- data/lib/active_model/serializer/{attributes.rb → concerns/attributes.rb} +0 -0
- data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +5 -1
- data/lib/active_model/serializer/{configuration.rb → concerns/configuration.rb} +24 -1
- data/lib/active_model/serializer/{links.rb → concerns/links.rb} +0 -0
- data/lib/active_model/serializer/{meta.rb → concerns/meta.rb} +0 -0
- data/lib/active_model/serializer/{type.rb → concerns/type.rb} +0 -0
- data/lib/active_model/serializer/reflection.rb +37 -21
- data/lib/active_model/serializer/version.rb +1 -1
- data/lib/active_model_serializers.rb +1 -0
- data/lib/active_model_serializers/adapter/attributes.rb +3 -1
- data/lib/active_model_serializers/adapter/json_api.rb +15 -22
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +30 -19
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +23 -9
- data/lib/active_model_serializers/key_transform.rb +4 -0
- data/lib/active_model_serializers/lookup_chain.rb +80 -0
- data/lib/active_model_serializers/model.rb +1 -1
- data/lib/active_model_serializers/serializable_resource.rb +6 -5
- data/lib/generators/rails/serializer_generator.rb +1 -1
- data/test/action_controller/json_api/fields_test.rb +57 -0
- data/test/action_controller/json_api/transform_test.rb +3 -3
- data/test/action_controller/lookup_proc_test.rb +49 -0
- data/test/action_controller/namespace_lookup_test.rb +226 -0
- data/test/active_model_serializers/key_transform_test.rb +32 -0
- data/test/active_model_serializers/model_test.rb +11 -0
- data/test/adapter/attributes_test.rb +43 -0
- data/test/adapter/json/transform_test.rb +1 -1
- data/test/adapter/json_api/fields_test.rb +4 -3
- data/test/adapter/json_api/has_many_test.rb +21 -0
- data/test/adapter/json_api/include_data_if_sideloaded_test.rb +166 -0
- data/test/adapter/json_api/linked_test.rb +24 -6
- data/test/adapter/json_api/links_test.rb +1 -1
- data/test/adapter/json_api/pagination_links_test.rb +17 -2
- data/test/adapter/json_api/relationship_test.rb +309 -73
- data/test/adapter/json_api/resource_identifier_test.rb +20 -0
- data/test/adapter/json_api/transform_test.rb +4 -3
- data/test/benchmark/benchmarking_support.rb +1 -1
- data/test/benchmark/bm_active_record.rb +81 -0
- data/test/benchmark/bm_adapter.rb +38 -0
- data/test/benchmark/bm_caching.rb +1 -1
- data/test/benchmark/bm_lookup_chain.rb +83 -0
- data/test/cache_test.rb +42 -4
- data/test/collection_serializer_test.rb +1 -1
- data/test/fixtures/poro.rb +44 -41
- data/test/generators/serializer_generator_test.rb +22 -5
- data/test/serializers/association_macros_test.rb +3 -2
- data/test/serializers/associations_test.rb +97 -22
- data/test/serializers/attribute_test.rb +1 -1
- data/test/serializers/serializer_for_test.rb +3 -3
- data/test/serializers/serializer_for_with_namespace_test.rb +87 -0
- data/test/support/serialization_testing.rb +16 -0
- data/test/test_helper.rb +1 -0
- metadata +35 -14
- data/test/adapter/json_api/relationships_test.rb +0 -204
@@ -5,7 +5,9 @@ module ActionController
|
|
5
5
|
class JsonApi
|
6
6
|
class KeyTransformTest < ActionController::TestCase
|
7
7
|
class KeyTransformTestController < ActionController::Base
|
8
|
-
Post
|
8
|
+
class Post < ::Model; end
|
9
|
+
class Author < ::Model; end
|
10
|
+
class TopComment < ::Model; end
|
9
11
|
class PostSerializer < ActiveModel::Serializer
|
10
12
|
type 'posts'
|
11
13
|
attributes :title, :body, :publish_at
|
@@ -22,13 +24,11 @@ module ActionController
|
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
|
-
Author = Class.new(::Model)
|
26
27
|
class AuthorSerializer < ActiveModel::Serializer
|
27
28
|
type 'authors'
|
28
29
|
attributes :first_name, :last_name
|
29
30
|
end
|
30
31
|
|
31
|
-
TopComment = Class.new(::Model)
|
32
32
|
class TopCommentSerializer < ActiveModel::Serializer
|
33
33
|
type 'top_comments'
|
34
34
|
attributes :body
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
module Serialization
|
5
|
+
class LookupProcTest < ActionController::TestCase
|
6
|
+
module Api
|
7
|
+
module V3
|
8
|
+
class PostCustomSerializer < ActiveModel::Serializer
|
9
|
+
attributes :title, :body
|
10
|
+
|
11
|
+
belongs_to :author
|
12
|
+
end
|
13
|
+
|
14
|
+
class AuthorCustomSerializer < ActiveModel::Serializer
|
15
|
+
attributes :name
|
16
|
+
end
|
17
|
+
|
18
|
+
class LookupProcTestController < ActionController::Base
|
19
|
+
def implicit_namespaced_serializer
|
20
|
+
author = Author.new(name: 'Bob')
|
21
|
+
post = Post.new(title: 'New Post', body: 'Body', author: author)
|
22
|
+
|
23
|
+
render json: post
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
tests Api::V3::LookupProcTestController
|
30
|
+
|
31
|
+
test 'implicitly uses namespaced serializer' do
|
32
|
+
controller_namespace = lambda do |resource_class, _parent_serializer_class, namespace|
|
33
|
+
"#{namespace}::#{resource_class}CustomSerializer" if namespace
|
34
|
+
end
|
35
|
+
|
36
|
+
with_prepended_lookup(controller_namespace) do
|
37
|
+
get :implicit_namespaced_serializer
|
38
|
+
|
39
|
+
assert_serializer Api::V3::PostCustomSerializer
|
40
|
+
|
41
|
+
expected = { 'title' => 'New Post', 'body' => 'Body', 'author' => { 'name' => 'Bob' } }
|
42
|
+
actual = JSON.parse(@response.body)
|
43
|
+
|
44
|
+
assert_equal expected, actual
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
module Serialization
|
5
|
+
class NamespaceLookupTest < ActionController::TestCase
|
6
|
+
class Book < ::Model; end
|
7
|
+
class Page < ::Model; end
|
8
|
+
class Chapter < ::Model; end
|
9
|
+
class Writer < ::Model; end
|
10
|
+
|
11
|
+
module Api
|
12
|
+
module V2
|
13
|
+
class BookSerializer < ActiveModel::Serializer
|
14
|
+
attributes :title
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module VHeader
|
19
|
+
class BookSerializer < ActiveModel::Serializer
|
20
|
+
attributes :title, :body
|
21
|
+
|
22
|
+
def body
|
23
|
+
'header'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module V3
|
29
|
+
class BookSerializer < ActiveModel::Serializer
|
30
|
+
attributes :title, :body
|
31
|
+
|
32
|
+
belongs_to :writer
|
33
|
+
has_many :chapters
|
34
|
+
end
|
35
|
+
|
36
|
+
class ChapterSerializer < ActiveModel::Serializer
|
37
|
+
attribute :title do
|
38
|
+
"Chapter - #{object.title}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class WriterSerializer < ActiveModel::Serializer
|
43
|
+
attributes :name
|
44
|
+
end
|
45
|
+
|
46
|
+
class LookupTestController < ActionController::Base
|
47
|
+
before_action only: [:namespace_set_in_before_filter] do
|
48
|
+
self.namespace_for_serializer = Api::V2
|
49
|
+
end
|
50
|
+
|
51
|
+
def implicit_namespaced_serializer
|
52
|
+
writer = Writer.new(name: 'Bob')
|
53
|
+
book = Book.new(title: 'New Post', body: 'Body', writer: writer, chapters: [])
|
54
|
+
|
55
|
+
render json: book
|
56
|
+
end
|
57
|
+
|
58
|
+
def implicit_namespaced_collection_serializer
|
59
|
+
chapter1 = Chapter.new(title: 'Oh')
|
60
|
+
chapter2 = Chapter.new(title: 'Oh my')
|
61
|
+
|
62
|
+
render json: [chapter1, chapter2]
|
63
|
+
end
|
64
|
+
|
65
|
+
def implicit_has_many_namespaced_serializer
|
66
|
+
chapter1 = Chapter.new(title: 'Odd World')
|
67
|
+
chapter2 = Chapter.new(title: 'New World')
|
68
|
+
book = Book.new(title: 'New Post', body: 'Body', chapters: [chapter1, chapter2])
|
69
|
+
|
70
|
+
render json: book
|
71
|
+
end
|
72
|
+
|
73
|
+
def explicit_namespace_as_module
|
74
|
+
book = Book.new(title: 'New Post', body: 'Body')
|
75
|
+
|
76
|
+
render json: book, namespace: Api::V2
|
77
|
+
end
|
78
|
+
|
79
|
+
def explicit_namespace_as_string
|
80
|
+
book = Book.new(title: 'New Post', body: 'Body')
|
81
|
+
|
82
|
+
# because this is a string, ruby can't auto-lookup the constant, so otherwise
|
83
|
+
# the looku things we mean ::Api::V2
|
84
|
+
render json: book, namespace: 'ActionController::Serialization::NamespaceLookupTest::Api::V2'
|
85
|
+
end
|
86
|
+
|
87
|
+
def explicit_namespace_as_symbol
|
88
|
+
book = Book.new(title: 'New Post', body: 'Body')
|
89
|
+
|
90
|
+
# because this is a string, ruby can't auto-lookup the constant, so otherwise
|
91
|
+
# the looku things we mean ::Api::V2
|
92
|
+
render json: book, namespace: :'ActionController::Serialization::NamespaceLookupTest::Api::V2'
|
93
|
+
end
|
94
|
+
|
95
|
+
def invalid_namespace
|
96
|
+
book = Book.new(title: 'New Post', body: 'Body')
|
97
|
+
|
98
|
+
render json: book, namespace: :api_v2
|
99
|
+
end
|
100
|
+
|
101
|
+
def namespace_set_in_before_filter
|
102
|
+
book = Book.new(title: 'New Post', body: 'Body')
|
103
|
+
render json: book
|
104
|
+
end
|
105
|
+
|
106
|
+
def namespace_set_by_request_headers
|
107
|
+
book = Book.new(title: 'New Post', body: 'Body')
|
108
|
+
version_from_header = request.headers['X-API_VERSION']
|
109
|
+
namespace = "ActionController::Serialization::NamespaceLookupTest::#{version_from_header}"
|
110
|
+
|
111
|
+
render json: book, namespace: namespace
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
tests Api::V3::LookupTestController
|
118
|
+
|
119
|
+
setup do
|
120
|
+
@test_namespace = self.class.parent
|
121
|
+
end
|
122
|
+
|
123
|
+
test 'uses request headers to determine the namespace' do
|
124
|
+
request.env['X-API_VERSION'] = 'Api::VHeader'
|
125
|
+
get :namespace_set_by_request_headers
|
126
|
+
|
127
|
+
assert_serializer Api::VHeader::BookSerializer
|
128
|
+
end
|
129
|
+
|
130
|
+
test 'implicitly uses namespaced serializer' do
|
131
|
+
get :implicit_namespaced_serializer
|
132
|
+
|
133
|
+
assert_serializer Api::V3::BookSerializer
|
134
|
+
|
135
|
+
expected = { 'title' => 'New Post', 'body' => 'Body', 'writer' => { 'name' => 'Bob' }, 'chapters' => [] }
|
136
|
+
actual = JSON.parse(@response.body)
|
137
|
+
|
138
|
+
assert_equal expected, actual
|
139
|
+
end
|
140
|
+
|
141
|
+
test 'implicitly uses namespaced serializer for collection' do
|
142
|
+
get :implicit_namespaced_collection_serializer
|
143
|
+
|
144
|
+
assert_serializer 'ActiveModel::Serializer::CollectionSerializer'
|
145
|
+
|
146
|
+
expected = [{ 'title' => 'Chapter - Oh' }, { 'title' => 'Chapter - Oh my' }]
|
147
|
+
actual = JSON.parse(@response.body)
|
148
|
+
|
149
|
+
assert_equal expected, actual
|
150
|
+
end
|
151
|
+
|
152
|
+
test 'implicitly uses namespaced serializer for has_many' do
|
153
|
+
get :implicit_has_many_namespaced_serializer
|
154
|
+
|
155
|
+
assert_serializer Api::V3::BookSerializer
|
156
|
+
|
157
|
+
expected = {
|
158
|
+
'title' => 'New Post',
|
159
|
+
'body' => 'Body', 'writer' => nil,
|
160
|
+
'chapters' => [
|
161
|
+
{ 'title' => 'Chapter - Odd World' },
|
162
|
+
{ 'title' => 'Chapter - New World' }
|
163
|
+
]
|
164
|
+
}
|
165
|
+
actual = JSON.parse(@response.body)
|
166
|
+
|
167
|
+
assert_equal expected, actual
|
168
|
+
end
|
169
|
+
|
170
|
+
test 'explicit namespace as module' do
|
171
|
+
get :explicit_namespace_as_module
|
172
|
+
|
173
|
+
assert_serializer Api::V2::BookSerializer
|
174
|
+
|
175
|
+
expected = { 'title' => 'New Post' }
|
176
|
+
actual = JSON.parse(@response.body)
|
177
|
+
|
178
|
+
assert_equal expected, actual
|
179
|
+
end
|
180
|
+
|
181
|
+
test 'explicit namespace as string' do
|
182
|
+
get :explicit_namespace_as_string
|
183
|
+
|
184
|
+
assert_serializer Api::V2::BookSerializer
|
185
|
+
|
186
|
+
expected = { 'title' => 'New Post' }
|
187
|
+
actual = JSON.parse(@response.body)
|
188
|
+
|
189
|
+
assert_equal expected, actual
|
190
|
+
end
|
191
|
+
|
192
|
+
test 'explicit namespace as symbol' do
|
193
|
+
get :explicit_namespace_as_symbol
|
194
|
+
|
195
|
+
assert_serializer Api::V2::BookSerializer
|
196
|
+
|
197
|
+
expected = { 'title' => 'New Post' }
|
198
|
+
actual = JSON.parse(@response.body)
|
199
|
+
|
200
|
+
assert_equal expected, actual
|
201
|
+
end
|
202
|
+
|
203
|
+
test 'invalid namespace' do
|
204
|
+
get :invalid_namespace
|
205
|
+
|
206
|
+
assert_serializer ActiveModel::Serializer::Null
|
207
|
+
|
208
|
+
expected = { 'title' => 'New Post', 'body' => 'Body' }
|
209
|
+
actual = JSON.parse(@response.body)
|
210
|
+
|
211
|
+
assert_equal expected, actual
|
212
|
+
end
|
213
|
+
|
214
|
+
test 'namespace set in before filter' do
|
215
|
+
get :namespace_set_in_before_filter
|
216
|
+
|
217
|
+
assert_serializer Api::V2::BookSerializer
|
218
|
+
|
219
|
+
expected = { 'title' => 'New Post' }
|
220
|
+
actual = JSON.parse(@response.body)
|
221
|
+
|
222
|
+
assert_equal expected, actual
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -60,6 +60,14 @@ module ActiveModelSerializers
|
|
60
60
|
{
|
61
61
|
value: nil,
|
62
62
|
expected: nil
|
63
|
+
},
|
64
|
+
{
|
65
|
+
value: [
|
66
|
+
{ some_value: 'value' }
|
67
|
+
],
|
68
|
+
expected: [
|
69
|
+
{ SomeValue: 'value' }
|
70
|
+
]
|
63
71
|
}
|
64
72
|
]
|
65
73
|
scenarios.each do |s|
|
@@ -126,6 +134,14 @@ module ActiveModelSerializers
|
|
126
134
|
{
|
127
135
|
value: nil,
|
128
136
|
expected: nil
|
137
|
+
},
|
138
|
+
{
|
139
|
+
value: [
|
140
|
+
{ some_value: 'value' }
|
141
|
+
],
|
142
|
+
expected: [
|
143
|
+
{ someValue: 'value' }
|
144
|
+
]
|
129
145
|
}
|
130
146
|
]
|
131
147
|
scenarios.each do |s|
|
@@ -188,6 +204,14 @@ module ActiveModelSerializers
|
|
188
204
|
{
|
189
205
|
value: nil,
|
190
206
|
expected: nil
|
207
|
+
},
|
208
|
+
{
|
209
|
+
value: [
|
210
|
+
{ 'some_value' => 'value' }
|
211
|
+
],
|
212
|
+
expected: [
|
213
|
+
{ 'some-value' => 'value' }
|
214
|
+
]
|
191
215
|
}
|
192
216
|
]
|
193
217
|
scenarios.each do |s|
|
@@ -254,6 +278,14 @@ module ActiveModelSerializers
|
|
254
278
|
{
|
255
279
|
value: nil,
|
256
280
|
expected: nil
|
281
|
+
},
|
282
|
+
{
|
283
|
+
value: [
|
284
|
+
{ 'some-value' => 'value' }
|
285
|
+
],
|
286
|
+
expected: [
|
287
|
+
{ 'some_value' => 'value' }
|
288
|
+
]
|
257
289
|
}
|
258
290
|
]
|
259
291
|
scenarios.each do |s|
|
@@ -7,5 +7,16 @@ module ActiveModelSerializers
|
|
7
7
|
def setup
|
8
8
|
@resource = ActiveModelSerializers::Model.new
|
9
9
|
end
|
10
|
+
|
11
|
+
def test_initialization_with_string_keys
|
12
|
+
klass = Class.new(ActiveModelSerializers::Model) do
|
13
|
+
attr_accessor :key
|
14
|
+
end
|
15
|
+
value = 'value'
|
16
|
+
|
17
|
+
model_instance = klass.new('key' => value)
|
18
|
+
|
19
|
+
assert_equal model_instance.read_attribute_for_serialization(:key), value
|
20
|
+
end
|
10
21
|
end
|
11
22
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ActiveModelSerializers
|
4
|
+
module Adapter
|
5
|
+
class AttributesTest < ActiveSupport::TestCase
|
6
|
+
class Person
|
7
|
+
include ActiveModel::Model
|
8
|
+
include ActiveModel::Serialization
|
9
|
+
|
10
|
+
attr_accessor :first_name, :last_name
|
11
|
+
end
|
12
|
+
|
13
|
+
class PersonSerializer < ActiveModel::Serializer
|
14
|
+
attributes :first_name, :last_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup
|
18
|
+
ActionController::Base.cache_store.clear
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_serializable_hash
|
22
|
+
person = Person.new(first_name: 'Arthur', last_name: 'Dent')
|
23
|
+
serializer = PersonSerializer.new(person)
|
24
|
+
adapter = ActiveModelSerializers::Adapter::Attributes.new(serializer)
|
25
|
+
|
26
|
+
assert_equal({ first_name: 'Arthur', last_name: 'Dent' },
|
27
|
+
adapter.serializable_hash)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_serializable_hash_with_transform_key_casing
|
31
|
+
person = Person.new(first_name: 'Arthur', last_name: 'Dent')
|
32
|
+
serializer = PersonSerializer.new(person)
|
33
|
+
adapter = ActiveModelSerializers::Adapter::Attributes.new(
|
34
|
+
serializer,
|
35
|
+
key_transform: :camel_lower
|
36
|
+
)
|
37
|
+
|
38
|
+
assert_equal({ firstName: 'Arthur', lastName: 'Dent' },
|
39
|
+
adapter.serializable_hash)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -15,7 +15,7 @@ module ActiveModelSerializers
|
|
15
15
|
@adapter = ActiveModelSerializers::Adapter::Json.new(serializer, options)
|
16
16
|
end
|
17
17
|
|
18
|
-
Post
|
18
|
+
class Post < ::Model; end
|
19
19
|
class PostSerializer < ActiveModel::Serializer
|
20
20
|
attributes :id, :title, :body, :publish_at
|
21
21
|
end
|
@@ -4,7 +4,10 @@ module ActiveModelSerializers
|
|
4
4
|
module Adapter
|
5
5
|
class JsonApi
|
6
6
|
class FieldsTest < ActiveSupport::TestCase
|
7
|
-
Post
|
7
|
+
class Post < ::Model; end
|
8
|
+
class Author < ::Model; end
|
9
|
+
class Comment < ::Model; end
|
10
|
+
|
8
11
|
class PostSerializer < ActiveModel::Serializer
|
9
12
|
type 'posts'
|
10
13
|
attributes :title, :body
|
@@ -12,13 +15,11 @@ module ActiveModelSerializers
|
|
12
15
|
has_many :comments
|
13
16
|
end
|
14
17
|
|
15
|
-
Author = Class.new(::Model)
|
16
18
|
class AuthorSerializer < ActiveModel::Serializer
|
17
19
|
type 'authors'
|
18
20
|
attributes :name, :birthday
|
19
21
|
end
|
20
22
|
|
21
|
-
Comment = Class.new(::Model)
|
22
23
|
class CommentSerializer < ActiveModel::Serializer
|
23
24
|
type 'comments'
|
24
25
|
attributes :body
|