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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.travis.yml +26 -0
  4. data/CHANGELOG.md +8 -0
  5. data/CONTRIBUTING.md +31 -0
  6. data/Gemfile +17 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +326 -0
  9. data/Rakefile +12 -0
  10. data/cm-active_model_serializers.gemspec +26 -0
  11. data/lib/action_controller/serialization.rb +62 -0
  12. data/lib/active_model/serializer.rb +261 -0
  13. data/lib/active_model/serializer/adapter.rb +87 -0
  14. data/lib/active_model/serializer/adapter/fragment_cache.rb +78 -0
  15. data/lib/active_model/serializer/adapter/json.rb +52 -0
  16. data/lib/active_model/serializer/adapter/json/fragment_cache.rb +15 -0
  17. data/lib/active_model/serializer/adapter/json_api.rb +152 -0
  18. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +22 -0
  19. data/lib/active_model/serializer/adapter/null.rb +11 -0
  20. data/lib/active_model/serializer/array_serializer.rb +32 -0
  21. data/lib/active_model/serializer/configuration.rb +13 -0
  22. data/lib/active_model/serializer/fieldset.rb +40 -0
  23. data/lib/active_model/serializer/version.rb +5 -0
  24. data/lib/active_model_serializers.rb +18 -0
  25. data/lib/generators/serializer/USAGE +6 -0
  26. data/lib/generators/serializer/serializer_generator.rb +37 -0
  27. data/lib/generators/serializer/templates/serializer.rb +8 -0
  28. data/test/action_controller/adapter_selector_test.rb +51 -0
  29. data/test/action_controller/explicit_serializer_test.rb +110 -0
  30. data/test/action_controller/json_api_linked_test.rb +173 -0
  31. data/test/action_controller/serialization_scope_name_test.rb +63 -0
  32. data/test/action_controller/serialization_test.rb +365 -0
  33. data/test/adapter/fragment_cache_test.rb +27 -0
  34. data/test/adapter/json/belongs_to_test.rb +48 -0
  35. data/test/adapter/json/collection_test.rb +73 -0
  36. data/test/adapter/json/has_many_test.rb +36 -0
  37. data/test/adapter/json_api/belongs_to_test.rb +147 -0
  38. data/test/adapter/json_api/collection_test.rb +89 -0
  39. data/test/adapter/json_api/has_many_embed_ids_test.rb +45 -0
  40. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
  41. data/test/adapter/json_api/has_many_test.rb +106 -0
  42. data/test/adapter/json_api/has_one_test.rb +59 -0
  43. data/test/adapter/json_api/linked_test.rb +257 -0
  44. data/test/adapter/json_test.rb +34 -0
  45. data/test/adapter/null_test.rb +25 -0
  46. data/test/adapter_test.rb +43 -0
  47. data/test/array_serializer_test.rb +43 -0
  48. data/test/fixtures/poro.rb +213 -0
  49. data/test/serializers/adapter_for_test.rb +50 -0
  50. data/test/serializers/associations_test.rb +127 -0
  51. data/test/serializers/attribute_test.rb +38 -0
  52. data/test/serializers/attributes_test.rb +63 -0
  53. data/test/serializers/cache_test.rb +128 -0
  54. data/test/serializers/configuration_test.rb +15 -0
  55. data/test/serializers/fieldset_test.rb +26 -0
  56. data/test/serializers/generators_test.rb +59 -0
  57. data/test/serializers/meta_test.rb +78 -0
  58. data/test/serializers/options_test.rb +21 -0
  59. data/test/serializers/serializer_for_test.rb +65 -0
  60. data/test/serializers/urls_test.rb +26 -0
  61. data/test/test_helper.rb +38 -0
  62. metadata +195 -0
@@ -0,0 +1,6 @@
1
+ Description:
2
+ Generates a serializer for the given resource with tests.
3
+
4
+ Example:
5
+ `rails generate serializer Account name created_at`
6
+
@@ -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,8 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>Serializer < <%= parent_class_name %>
3
+ attributes <%= attributes_names.map(&:inspect).join(", ") %>
4
+ end
5
+ <% association_names.each do |attribute| -%>
6
+ attribute :<%= attribute %>
7
+ <% end -%>
8
+ <% end -%>
@@ -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