cm-active_model_serializers 0.10.0.rc1.1
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 +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +26 -0
- data/CHANGELOG.md +8 -0
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +22 -0
- data/README.md +326 -0
- data/Rakefile +12 -0
- data/cm-active_model_serializers.gemspec +26 -0
- data/lib/action_controller/serialization.rb +62 -0
- data/lib/active_model/serializer.rb +261 -0
- data/lib/active_model/serializer/adapter.rb +87 -0
- data/lib/active_model/serializer/adapter/fragment_cache.rb +78 -0
- data/lib/active_model/serializer/adapter/json.rb +52 -0
- data/lib/active_model/serializer/adapter/json/fragment_cache.rb +15 -0
- data/lib/active_model/serializer/adapter/json_api.rb +152 -0
- data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +22 -0
- data/lib/active_model/serializer/adapter/null.rb +11 -0
- data/lib/active_model/serializer/array_serializer.rb +32 -0
- data/lib/active_model/serializer/configuration.rb +13 -0
- data/lib/active_model/serializer/fieldset.rb +40 -0
- data/lib/active_model/serializer/version.rb +5 -0
- data/lib/active_model_serializers.rb +18 -0
- data/lib/generators/serializer/USAGE +6 -0
- data/lib/generators/serializer/serializer_generator.rb +37 -0
- data/lib/generators/serializer/templates/serializer.rb +8 -0
- data/test/action_controller/adapter_selector_test.rb +51 -0
- data/test/action_controller/explicit_serializer_test.rb +110 -0
- data/test/action_controller/json_api_linked_test.rb +173 -0
- data/test/action_controller/serialization_scope_name_test.rb +63 -0
- data/test/action_controller/serialization_test.rb +365 -0
- data/test/adapter/fragment_cache_test.rb +27 -0
- data/test/adapter/json/belongs_to_test.rb +48 -0
- data/test/adapter/json/collection_test.rb +73 -0
- data/test/adapter/json/has_many_test.rb +36 -0
- data/test/adapter/json_api/belongs_to_test.rb +147 -0
- data/test/adapter/json_api/collection_test.rb +89 -0
- data/test/adapter/json_api/has_many_embed_ids_test.rb +45 -0
- data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
- data/test/adapter/json_api/has_many_test.rb +106 -0
- data/test/adapter/json_api/has_one_test.rb +59 -0
- data/test/adapter/json_api/linked_test.rb +257 -0
- data/test/adapter/json_test.rb +34 -0
- data/test/adapter/null_test.rb +25 -0
- data/test/adapter_test.rb +43 -0
- data/test/array_serializer_test.rb +43 -0
- data/test/fixtures/poro.rb +213 -0
- data/test/serializers/adapter_for_test.rb +50 -0
- data/test/serializers/associations_test.rb +127 -0
- data/test/serializers/attribute_test.rb +38 -0
- data/test/serializers/attributes_test.rb +63 -0
- data/test/serializers/cache_test.rb +128 -0
- data/test/serializers/configuration_test.rb +15 -0
- data/test/serializers/fieldset_test.rb +26 -0
- data/test/serializers/generators_test.rb +59 -0
- data/test/serializers/meta_test.rb +78 -0
- data/test/serializers/options_test.rb +21 -0
- data/test/serializers/serializer_for_test.rb +65 -0
- data/test/serializers/urls_test.rb +26 -0
- data/test/test_helper.rb +38 -0
- metadata +195 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module Rails
|
2
|
+
module Generators
|
3
|
+
class SerializerGenerator < NamedBase
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
check_class_collision :suffix => "Serializer"
|
6
|
+
|
7
|
+
argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
|
8
|
+
|
9
|
+
class_option :parent, :type => :string, :desc => "The parent class for the generated serializer"
|
10
|
+
|
11
|
+
def create_serializer_file
|
12
|
+
template 'serializer.rb', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def attributes_names
|
18
|
+
[:id] + attributes.select { |attr| !attr.reference? }.map { |a| a.name.to_sym }
|
19
|
+
end
|
20
|
+
|
21
|
+
def association_names
|
22
|
+
attributes.select { |attr| attr.reference? }.map { |a| a.name.to_sym }
|
23
|
+
end
|
24
|
+
|
25
|
+
def parent_class_name
|
26
|
+
if options[:parent]
|
27
|
+
options[:parent]
|
28
|
+
elsif defined?(::ApplicationSerializer)
|
29
|
+
"ApplicationSerializer"
|
30
|
+
else
|
31
|
+
"ActiveModel::Serializer"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
module Serialization
|
5
|
+
class AdapterSelectorTest < ActionController::TestCase
|
6
|
+
class MyController < ActionController::Base
|
7
|
+
def render_using_default_adapter
|
8
|
+
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
9
|
+
render json: @profile
|
10
|
+
end
|
11
|
+
|
12
|
+
def render_using_adapter_override
|
13
|
+
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
14
|
+
render json: @profile, adapter: :json_api
|
15
|
+
end
|
16
|
+
|
17
|
+
def render_skipping_adapter
|
18
|
+
@profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
|
19
|
+
render json: @profile, adapter: false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
tests MyController
|
24
|
+
|
25
|
+
def test_render_using_default_adapter
|
26
|
+
get :render_using_default_adapter
|
27
|
+
assert_equal '{"name":"Name 1","description":"Description 1"}', response.body
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_render_using_adapter_override
|
31
|
+
get :render_using_adapter_override
|
32
|
+
|
33
|
+
expected = {
|
34
|
+
data: {
|
35
|
+
name: "Name 1",
|
36
|
+
description: "Description 1",
|
37
|
+
id: assigns(:profile).id.to_s,
|
38
|
+
type: "profiles"
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
assert_equal expected.to_json, response.body
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_render_skipping_adapter
|
46
|
+
get :render_skipping_adapter
|
47
|
+
assert_equal '{"attributes":{"name":"Name 1","description":"Description 1","comments":"Comments 1"}}', response.body
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
module Serialization
|
5
|
+
class ExplicitSerializerTest < ActionController::TestCase
|
6
|
+
class MyController < ActionController::Base
|
7
|
+
def render_using_explicit_serializer
|
8
|
+
@profile = Profile.new(name: 'Name 1',
|
9
|
+
description: 'Description 1',
|
10
|
+
comments: 'Comments 1')
|
11
|
+
render json: @profile, serializer: ProfilePreviewSerializer
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_array_using_explicit_serializer
|
15
|
+
array = [
|
16
|
+
Profile.new(name: 'Name 1',
|
17
|
+
description: 'Description 1',
|
18
|
+
comments: 'Comments 1'),
|
19
|
+
Profile.new(name: 'Name 2',
|
20
|
+
description: 'Description 2',
|
21
|
+
comments: 'Comments 2')
|
22
|
+
]
|
23
|
+
render json: array,
|
24
|
+
serializer: PaginatedSerializer,
|
25
|
+
each_serializer: ProfilePreviewSerializer
|
26
|
+
end
|
27
|
+
|
28
|
+
def render_array_using_implicit_serializer
|
29
|
+
array = [
|
30
|
+
Profile.new(name: 'Name 1',
|
31
|
+
description: 'Description 1',
|
32
|
+
comments: 'Comments 1'),
|
33
|
+
Profile.new(name: 'Name 2',
|
34
|
+
description: 'Description 2',
|
35
|
+
comments: 'Comments 2')
|
36
|
+
]
|
37
|
+
render json: array,
|
38
|
+
each_serializer: ProfilePreviewSerializer
|
39
|
+
end
|
40
|
+
|
41
|
+
def render_array_using_explicit_serializer_and_custom_serializers
|
42
|
+
@post = Post.new(title: 'New Post', body: 'Body')
|
43
|
+
@author = Author.new(name: 'Jane Blogger')
|
44
|
+
@author.posts = [@post]
|
45
|
+
@post.author = @author
|
46
|
+
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
47
|
+
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
48
|
+
@post.comments = [@first_comment, @second_comment]
|
49
|
+
@first_comment.post = @post
|
50
|
+
@first_comment.author = nil
|
51
|
+
@second_comment.post = @post
|
52
|
+
@second_comment.author = nil
|
53
|
+
@blog = Blog.new(id: 23, name: 'AMS Blog')
|
54
|
+
@post.blog = @blog
|
55
|
+
|
56
|
+
render json: [@post], each_serializer: PostPreviewSerializer
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
tests MyController
|
61
|
+
|
62
|
+
def test_render_using_explicit_serializer
|
63
|
+
get :render_using_explicit_serializer
|
64
|
+
|
65
|
+
assert_equal 'application/json', @response.content_type
|
66
|
+
assert_equal '{"name":"Name 1"}', @response.body
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_render_array_using_explicit_serializer
|
70
|
+
get :render_array_using_explicit_serializer
|
71
|
+
assert_equal 'application/json', @response.content_type
|
72
|
+
|
73
|
+
expected = {
|
74
|
+
'paginated' => [
|
75
|
+
{ 'name' => 'Name 1' },
|
76
|
+
{ 'name' => 'Name 2' }
|
77
|
+
]
|
78
|
+
}
|
79
|
+
|
80
|
+
assert_equal expected.to_json, @response.body
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_render_array_using_implicit_serializer
|
84
|
+
get :render_array_using_implicit_serializer
|
85
|
+
assert_equal 'application/json', @response.content_type
|
86
|
+
|
87
|
+
expected = [
|
88
|
+
{ 'name' => 'Name 1' },
|
89
|
+
{ 'name' => 'Name 2' }
|
90
|
+
]
|
91
|
+
assert_equal expected.to_json, @response.body
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_render_array_using_explicit_serializer_and_custom_serializers
|
95
|
+
get :render_array_using_explicit_serializer_and_custom_serializers
|
96
|
+
|
97
|
+
expected = [
|
98
|
+
{ "title" => "New Post",
|
99
|
+
"body" => "Body",
|
100
|
+
"id" => assigns(:post).id,
|
101
|
+
"comments" => [{"id" => 1}, {"id" => 2}],
|
102
|
+
"author" => { "id" => assigns(:author).id }
|
103
|
+
}
|
104
|
+
]
|
105
|
+
|
106
|
+
assert_equal expected.to_json, @response.body
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
module Serialization
|
5
|
+
class JsonApiLinkedTest < ActionController::TestCase
|
6
|
+
class MyController < ActionController::Base
|
7
|
+
def setup_post
|
8
|
+
ActionController::Base.cache_store.clear
|
9
|
+
@role1 = Role.new(id: 1, name: 'admin')
|
10
|
+
@role2 = Role.new(id: 2, name: 'colab')
|
11
|
+
@author = Author.new(id: 1, name: 'Steve K.')
|
12
|
+
@author.posts = []
|
13
|
+
@author.bio = nil
|
14
|
+
@author.roles = [@role1, @role2]
|
15
|
+
@role1.author = @author
|
16
|
+
@role2.author = @author
|
17
|
+
@author2 = Author.new(id: 2, name: 'Anonymous')
|
18
|
+
@author2.posts = []
|
19
|
+
@author2.bio = nil
|
20
|
+
@author2.roles = []
|
21
|
+
@post = Post.new(id: 1, title: 'New Post', body: 'Body')
|
22
|
+
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
23
|
+
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
|
24
|
+
@post.comments = [@first_comment, @second_comment]
|
25
|
+
@post.author = @author
|
26
|
+
@first_comment.post = @post
|
27
|
+
@first_comment.author = @author2
|
28
|
+
@second_comment.post = @post
|
29
|
+
@second_comment.author = nil
|
30
|
+
@post2 = Post.new(id: 2, title: "Another Post", body: "Body")
|
31
|
+
@post2.author = @author
|
32
|
+
@post2.comments = []
|
33
|
+
@blog = Blog.new(id: 1, name: "My Blog!!")
|
34
|
+
@post.blog = @blog
|
35
|
+
@post2.blog = @blog
|
36
|
+
end
|
37
|
+
|
38
|
+
def render_resource_without_include
|
39
|
+
setup_post
|
40
|
+
render json: @post, adapter: :json_api
|
41
|
+
end
|
42
|
+
|
43
|
+
def render_resource_with_include
|
44
|
+
setup_post
|
45
|
+
render json: @post, include: 'author', adapter: :json_api
|
46
|
+
end
|
47
|
+
|
48
|
+
def render_resource_with_nested_include
|
49
|
+
setup_post
|
50
|
+
render json: @post, include: 'comments.author', adapter: :json_api
|
51
|
+
end
|
52
|
+
|
53
|
+
def render_resource_with_nested_has_many_include
|
54
|
+
setup_post
|
55
|
+
render json: @post, include: ['author', 'author.roles'], adapter: :json_api
|
56
|
+
end
|
57
|
+
|
58
|
+
def render_resource_with_missing_nested_has_many_include
|
59
|
+
setup_post
|
60
|
+
@post.author = @author2 # author2 has no roles.
|
61
|
+
render json: @post, include: 'author,author.roles', adapter: :json_api
|
62
|
+
end
|
63
|
+
|
64
|
+
def render_collection_with_missing_nested_has_many_include
|
65
|
+
setup_post
|
66
|
+
@post.author = @author2
|
67
|
+
render json: [@post, @post2], include: 'author,author.roles', adapter: :json_api
|
68
|
+
end
|
69
|
+
|
70
|
+
def render_collection_without_include
|
71
|
+
setup_post
|
72
|
+
render json: [@post], adapter: :json_api
|
73
|
+
end
|
74
|
+
|
75
|
+
def render_collection_with_include
|
76
|
+
setup_post
|
77
|
+
render json: [@post], include: ['author', 'comments'], adapter: :json_api
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
tests MyController
|
82
|
+
|
83
|
+
def test_render_resource_without_include
|
84
|
+
get :render_resource_without_include
|
85
|
+
response = JSON.parse(@response.body)
|
86
|
+
refute response.key? 'included'
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_render_resource_with_include
|
90
|
+
get :render_resource_with_include
|
91
|
+
response = JSON.parse(@response.body)
|
92
|
+
assert response.key? 'included'
|
93
|
+
assert_equal 1, response['included'].size
|
94
|
+
assert_equal 'Steve K.', response['included'].first['name']
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_render_resource_with_nested_has_many_include
|
98
|
+
get :render_resource_with_nested_has_many_include
|
99
|
+
response = JSON.parse(@response.body)
|
100
|
+
expected_linked = [
|
101
|
+
{
|
102
|
+
"id" => "1",
|
103
|
+
"type" => "authors",
|
104
|
+
"name" => "Steve K.",
|
105
|
+
"links" => {
|
106
|
+
"posts" => { "linkage" => [] },
|
107
|
+
"roles" => { "linkage" => [{ "type" =>"roles", "id" => "1" }, { "type" =>"roles", "id" => "2" }] },
|
108
|
+
"bio" => { "linkage" => nil }
|
109
|
+
}
|
110
|
+
}, {
|
111
|
+
"id" => "1",
|
112
|
+
"type" => "roles",
|
113
|
+
"name" => "admin",
|
114
|
+
"description" => nil,
|
115
|
+
"slug" => "admin-1",
|
116
|
+
"links" => {
|
117
|
+
"author" => { "linkage" => { "type" =>"authors", "id" => "1" } }
|
118
|
+
}
|
119
|
+
}, {
|
120
|
+
"id" => "2",
|
121
|
+
"type" => "roles",
|
122
|
+
"name" => "colab",
|
123
|
+
"description" => nil,
|
124
|
+
"slug" => "colab-2",
|
125
|
+
"links" => {
|
126
|
+
"author" => { "linkage" => { "type" =>"authors", "id" => "1" } }
|
127
|
+
}
|
128
|
+
}
|
129
|
+
]
|
130
|
+
assert_equal expected_linked, response['included']
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_render_resource_with_nested_include
|
134
|
+
get :render_resource_with_nested_include
|
135
|
+
response = JSON.parse(@response.body)
|
136
|
+
assert response.key? 'included'
|
137
|
+
assert_equal 1, response['included'].size
|
138
|
+
assert_equal 'Anonymous', response['included'].first['name']
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_render_collection_without_include
|
142
|
+
get :render_collection_without_include
|
143
|
+
response = JSON.parse(@response.body)
|
144
|
+
refute response.key? 'included'
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_render_collection_with_include
|
148
|
+
get :render_collection_with_include
|
149
|
+
response = JSON.parse(@response.body)
|
150
|
+
assert response.key? 'included'
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_render_resource_with_nested_attributes_even_when_missing_associations
|
154
|
+
get :render_resource_with_missing_nested_has_many_include
|
155
|
+
response = JSON.parse(@response.body)
|
156
|
+
assert response.key? 'included'
|
157
|
+
refute has_type?(response['included'], 'roles')
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_render_collection_with_missing_nested_has_many_include
|
161
|
+
get :render_collection_with_missing_nested_has_many_include
|
162
|
+
response = JSON.parse(@response.body)
|
163
|
+
assert response.key? 'included'
|
164
|
+
assert has_type?(response['included'], 'roles')
|
165
|
+
end
|
166
|
+
|
167
|
+
def has_type?(collection, value)
|
168
|
+
collection.detect { |i| i['type'] == value}
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
class DefaultScopeNameTest < ActionController::TestCase
|
5
|
+
class UserSerializer < ActiveModel::Serializer
|
6
|
+
attributes :admin?
|
7
|
+
def admin?
|
8
|
+
current_user.admin
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class UserTestController < ActionController::Base
|
13
|
+
protect_from_forgery
|
14
|
+
|
15
|
+
before_filter { request.format = :json }
|
16
|
+
|
17
|
+
def current_user
|
18
|
+
User.new(id: 1, name: 'Pete', admin: false)
|
19
|
+
end
|
20
|
+
|
21
|
+
def render_new_user
|
22
|
+
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: UserSerializer, adapter: :json_api
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
tests UserTestController
|
27
|
+
|
28
|
+
def test_default_scope_name
|
29
|
+
get :render_new_user
|
30
|
+
assert_equal '{"data":{"admin?":false,"id":"1","type":"users"}}', @response.body
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class SerializationScopeNameTest < ActionController::TestCase
|
35
|
+
class AdminUserSerializer < ActiveModel::Serializer
|
36
|
+
attributes :admin?
|
37
|
+
def admin?
|
38
|
+
current_admin.admin
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class AdminUserTestController < ActionController::Base
|
43
|
+
protect_from_forgery
|
44
|
+
|
45
|
+
serialization_scope :current_admin
|
46
|
+
before_filter { request.format = :json }
|
47
|
+
|
48
|
+
def current_admin
|
49
|
+
User.new(id: 2, name: 'Bob', admin: true)
|
50
|
+
end
|
51
|
+
|
52
|
+
def render_new_user
|
53
|
+
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: AdminUserSerializer, adapter: :json_api
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
tests AdminUserTestController
|
58
|
+
|
59
|
+
def test_override_scope_name_with_controller
|
60
|
+
get :render_new_user
|
61
|
+
assert_equal '{"data":{"admin?":true,"id":"1","type":"users"}}', @response.body
|
62
|
+
end
|
63
|
+
end
|