active_model_serializers 0.9.0 → 0.9.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/CHANGELOG.md +6 -0
- data/README.md +109 -17
- data/lib/action_controller/serialization.rb +27 -8
- data/lib/action_controller/serialization_test_case.rb +4 -4
- data/lib/active_model/array_serializer.rb +12 -5
- data/lib/active_model/serializable.rb +24 -2
- data/lib/active_model/serializable/utils.rb +16 -0
- data/lib/active_model/serializer.rb +70 -36
- data/lib/active_model/serializer/{associations.rb → association.rb} +8 -52
- data/lib/active_model/serializer/association/has_many.rb +39 -0
- data/lib/active_model/serializer/association/has_one.rb +25 -0
- data/lib/active_model/serializer/railtie.rb +8 -0
- data/lib/active_model/serializer/version.rb +1 -1
- data/lib/active_model_serializers.rb +1 -1
- data/test/fixtures/poro.rb +106 -1
- data/test/fixtures/template.html.erb +1 -0
- data/test/integration/action_controller/namespaced_serialization_test.rb +96 -0
- data/test/integration/action_controller/serialization_test_case_test.rb +10 -0
- data/test/integration/active_record/active_record_test.rb +2 -2
- data/test/serializers/tmp/app/serializers/account_serializer.rb +3 -0
- data/test/test_app.rb +3 -0
- data/test/unit/active_model/array_serializer/serialization_test.rb +1 -1
- data/test/unit/active_model/serializer/associations/build_serializer_test.rb +15 -0
- data/test/unit/active_model/serializer/attributes_test.rb +16 -0
- data/test/unit/active_model/serializer/config_test.rb +3 -0
- data/test/unit/active_model/serializer/has_many_polymorphic_test.rb +189 -0
- data/test/unit/active_model/serializer/has_many_test.rb +51 -16
- data/test/unit/active_model/serializer/has_one_and_has_many_test.rb +27 -0
- data/test/unit/active_model/serializer/has_one_polymorphic_test.rb +196 -0
- data/test/unit/active_model/serializer/has_one_test.rb +32 -0
- data/test/unit/active_model/serializer/options_test.rb +19 -0
- data/test/unit/active_model/serializer/url_helpers_test.rb +35 -0
- metadata +44 -27
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'active_model/default_serializer'
|
2
|
+
require 'active_model/serializer/association/has_one'
|
3
|
+
require 'active_model/serializer/association/has_many'
|
2
4
|
|
3
5
|
module ActiveModel
|
4
6
|
class Serializer
|
@@ -13,6 +15,7 @@ module ActiveModel
|
|
13
15
|
@name = name.to_s
|
14
16
|
@options = options
|
15
17
|
self.embed = options.fetch(:embed) { CONFIG.embed }
|
18
|
+
@polymorphic = options.fetch(:polymorphic, false)
|
16
19
|
@embed_in_root = options.fetch(:embed_in_root) { options.fetch(:include) { CONFIG.embed_in_root } }
|
17
20
|
@key_format = options.fetch(:key_format) { CONFIG.key_format }
|
18
21
|
@embed_key = options[:embed_key] || :id
|
@@ -25,21 +28,22 @@ module ActiveModel
|
|
25
28
|
@serializer_from_options = serializer.is_a?(String) ? serializer.constantize : serializer
|
26
29
|
end
|
27
30
|
|
28
|
-
attr_reader :name, :embed_ids, :embed_objects
|
31
|
+
attr_reader :name, :embed_ids, :embed_objects, :polymorphic
|
29
32
|
attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_from_options, :options, :key_format, :embed_in_root_key, :embed_namespace
|
30
33
|
alias embed_ids? embed_ids
|
31
34
|
alias embed_objects? embed_objects
|
32
35
|
alias embed_in_root? embed_in_root
|
33
36
|
alias embed_in_root_key? embed_in_root_key
|
34
37
|
alias embed_namespace? embed_namespace
|
38
|
+
alias polymorphic? polymorphic
|
35
39
|
|
36
40
|
def embed=(embed)
|
37
41
|
@embed_ids = embed == :id || embed == :ids
|
38
42
|
@embed_objects = embed == :object || embed == :objects
|
39
43
|
end
|
40
44
|
|
41
|
-
def serializer_from_object(object)
|
42
|
-
Serializer.serializer_for(object)
|
45
|
+
def serializer_from_object(object, options = {})
|
46
|
+
Serializer.serializer_for(object, options)
|
43
47
|
end
|
44
48
|
|
45
49
|
def default_serializer
|
@@ -47,55 +51,7 @@ module ActiveModel
|
|
47
51
|
end
|
48
52
|
|
49
53
|
def build_serializer(object, options = {})
|
50
|
-
serializer_class(object).new(object, options.merge(self.options))
|
51
|
-
end
|
52
|
-
|
53
|
-
class HasOne < Association
|
54
|
-
def initialize(name, *args)
|
55
|
-
super
|
56
|
-
@root_key = @embedded_key.to_s.pluralize
|
57
|
-
@key ||= "#{name}_id"
|
58
|
-
end
|
59
|
-
|
60
|
-
def serializer_class(object)
|
61
|
-
serializer_from_options || serializer_from_object(object) || default_serializer
|
62
|
-
end
|
63
|
-
|
64
|
-
def build_serializer(object, options = {})
|
65
|
-
options[:_wrap_in_array] = embed_in_root?
|
66
|
-
super
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
class HasMany < Association
|
71
|
-
def initialize(name, *args)
|
72
|
-
super
|
73
|
-
@root_key = @embedded_key
|
74
|
-
@key ||= "#{name.to_s.singularize}_ids"
|
75
|
-
end
|
76
|
-
|
77
|
-
def serializer_class(object)
|
78
|
-
if use_array_serializer?
|
79
|
-
ArraySerializer
|
80
|
-
else
|
81
|
-
serializer_from_options
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def options
|
86
|
-
if use_array_serializer?
|
87
|
-
{ each_serializer: serializer_from_options }.merge! super
|
88
|
-
else
|
89
|
-
super
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def use_array_serializer?
|
96
|
-
!serializer_from_options ||
|
97
|
-
serializer_from_options && !(serializer_from_options <= ArraySerializer)
|
98
|
-
end
|
54
|
+
serializer_class(object, options).new(object, options.merge(self.options))
|
99
55
|
end
|
100
56
|
end
|
101
57
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
class Serializer
|
3
|
+
class Association
|
4
|
+
class HasMany < Association
|
5
|
+
def initialize(name, *args)
|
6
|
+
super
|
7
|
+
@root_key = @embedded_key.to_s
|
8
|
+
@key ||= case CONFIG.default_key_type
|
9
|
+
when :name then name.to_s.pluralize
|
10
|
+
else "#{name.to_s.singularize}_ids"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def serializer_class(object, _)
|
15
|
+
if use_array_serializer?
|
16
|
+
ArraySerializer
|
17
|
+
else
|
18
|
+
serializer_from_options
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def options
|
23
|
+
if use_array_serializer?
|
24
|
+
{ each_serializer: serializer_from_options }.merge! super
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def use_array_serializer?
|
33
|
+
!serializer_from_options ||
|
34
|
+
serializer_from_options && !(serializer_from_options <= ArraySerializer)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
class Serializer
|
3
|
+
class Association
|
4
|
+
class HasOne < Association
|
5
|
+
def initialize(name, *args)
|
6
|
+
super
|
7
|
+
@root_key = @embedded_key.to_s.pluralize
|
8
|
+
@key ||= case CONFIG.default_key_type
|
9
|
+
when :name then name.to_s.singularize
|
10
|
+
else "#{name}_id"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def serializer_class(object, options = {})
|
15
|
+
serializer_from_options || serializer_from_object(object, options) || default_serializer
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_serializer(object, options = {})
|
19
|
+
options[:_wrap_in_array] = embed_in_root?
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -6,5 +6,13 @@ module ActiveModel
|
|
6
6
|
require 'active_model/serializer/generators/serializer/scaffold_controller_generator'
|
7
7
|
require 'active_model/serializer/generators/resource_override'
|
8
8
|
end
|
9
|
+
|
10
|
+
initializer 'include_routes.active_model_serializer' do |app|
|
11
|
+
ActiveSupport.on_load(:active_model_serializers) do
|
12
|
+
include app.routes.url_helpers
|
13
|
+
end
|
14
|
+
end
|
9
15
|
end
|
10
16
|
end
|
17
|
+
|
18
|
+
ActiveSupport.run_load_hooks(:active_model_serializers, ActiveModel::Serializer)
|
@@ -9,7 +9,7 @@ begin
|
|
9
9
|
require 'action_controller/serialization'
|
10
10
|
require 'action_controller/serialization_test_case'
|
11
11
|
|
12
|
-
ActiveSupport.on_load(:
|
12
|
+
ActiveSupport.on_load(:action_controller) do
|
13
13
|
if ::ActionController::Serialization.enabled
|
14
14
|
ActionController::Base.send(:include, ::ActionController::Serialization)
|
15
15
|
ActionController::TestCase.send(:include, ::ActionController::SerializationAssertions)
|
data/test/fixtures/poro.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
class Model
|
2
|
-
def initialize(hash={})
|
2
|
+
def initialize(hash = {})
|
3
3
|
@attributes = hash
|
4
4
|
end
|
5
5
|
|
6
6
|
def read_attribute_for_serialization(name)
|
7
7
|
if name == :id || name == 'id'
|
8
8
|
object_id
|
9
|
+
elsif respond_to?(name)
|
10
|
+
send name
|
9
11
|
else
|
10
12
|
@attributes[name]
|
11
13
|
end
|
@@ -22,9 +24,22 @@ class User < Model
|
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
27
|
+
class UserInfo < Model
|
28
|
+
def user
|
29
|
+
@user ||= User.new(name: 'N1', email: 'E1')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
25
33
|
class Profile < Model
|
26
34
|
end
|
27
35
|
|
36
|
+
class Category < Model
|
37
|
+
def posts
|
38
|
+
@posts ||= [Post.new(title: 'T1', body: 'B1'),
|
39
|
+
Post.new(title: 'T2', body: 'B2')]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
28
43
|
class Post < Model
|
29
44
|
def comments
|
30
45
|
@comments ||= [Comment.new(content: 'C1'),
|
@@ -32,12 +47,37 @@ class Post < Model
|
|
32
47
|
end
|
33
48
|
end
|
34
49
|
|
50
|
+
class SpecialPost < Post
|
51
|
+
def special_comment
|
52
|
+
@speical_comment ||= Comment.new(content: 'special')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
35
56
|
class Comment < Model
|
36
57
|
end
|
37
58
|
|
38
59
|
class WebLog < Model
|
39
60
|
end
|
40
61
|
|
62
|
+
class Interview < Model
|
63
|
+
def attachment
|
64
|
+
@attachment ||= Image.new(url: 'U1')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Mail < Model
|
69
|
+
def attachments
|
70
|
+
@attachments ||= [Image.new(url: 'U1'),
|
71
|
+
Video.new(html: 'H1')]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Image < Model
|
76
|
+
end
|
77
|
+
|
78
|
+
class Video < Model
|
79
|
+
end
|
80
|
+
|
41
81
|
###
|
42
82
|
## Serializers
|
43
83
|
###
|
@@ -47,6 +87,10 @@ class UserSerializer < ActiveModel::Serializer
|
|
47
87
|
has_one :profile
|
48
88
|
end
|
49
89
|
|
90
|
+
class UserInfoSerializer < ActiveModel::Serializer
|
91
|
+
has_one :user
|
92
|
+
end
|
93
|
+
|
50
94
|
class ProfileSerializer < ActiveModel::Serializer
|
51
95
|
def description
|
52
96
|
description = object.read_attribute_for_serialization(:description)
|
@@ -56,12 +100,24 @@ class ProfileSerializer < ActiveModel::Serializer
|
|
56
100
|
attributes :name, :description
|
57
101
|
end
|
58
102
|
|
103
|
+
class CategorySerializer < ActiveModel::Serializer
|
104
|
+
attributes :name
|
105
|
+
|
106
|
+
has_many :posts
|
107
|
+
end
|
108
|
+
|
59
109
|
class PostSerializer < ActiveModel::Serializer
|
60
110
|
attributes :title, :body
|
61
111
|
|
62
112
|
has_many :comments
|
63
113
|
end
|
64
114
|
|
115
|
+
class SpecialPostSerializer < ActiveModel::Serializer
|
116
|
+
attributes :title, :body
|
117
|
+
has_many :comments, root: :comments, embed_in_root: true, embed: :ids
|
118
|
+
has_one :special_comment, root: :comments, embed_in_root: true, embed: :ids
|
119
|
+
end
|
120
|
+
|
65
121
|
class CommentSerializer < ActiveModel::Serializer
|
66
122
|
attributes :content
|
67
123
|
end
|
@@ -73,3 +129,52 @@ end
|
|
73
129
|
class WebLogLowerCamelSerializer < WebLogSerializer
|
74
130
|
format_keys :lower_camel
|
75
131
|
end
|
132
|
+
|
133
|
+
class InterviewSerializer < ActiveModel::Serializer
|
134
|
+
attributes :text
|
135
|
+
|
136
|
+
has_one :attachment, polymorphic: true
|
137
|
+
end
|
138
|
+
|
139
|
+
class MailSerializer < ActiveModel::Serializer
|
140
|
+
attributes :body
|
141
|
+
|
142
|
+
has_many :attachments, polymorphic: true
|
143
|
+
end
|
144
|
+
|
145
|
+
class ImageSerializer < ActiveModel::Serializer
|
146
|
+
attributes :url
|
147
|
+
end
|
148
|
+
|
149
|
+
class VideoSerializer < ActiveModel::Serializer
|
150
|
+
attributes :html
|
151
|
+
end
|
152
|
+
|
153
|
+
class ShortProfileSerializer < ::ProfileSerializer; end
|
154
|
+
|
155
|
+
module TestNamespace
|
156
|
+
class ProfileSerializer < ::ProfileSerializer; end
|
157
|
+
class UserSerializer < ::UserSerializer; end
|
158
|
+
end
|
159
|
+
|
160
|
+
ActiveModel::Serializer.setup do |config|
|
161
|
+
config.default_key_type = :name
|
162
|
+
end
|
163
|
+
|
164
|
+
class NameKeyUserSerializer < ActiveModel::Serializer
|
165
|
+
attributes :name, :email
|
166
|
+
|
167
|
+
has_one :profile
|
168
|
+
end
|
169
|
+
|
170
|
+
class NameKeyPostSerializer < ActiveModel::Serializer
|
171
|
+
attributes :title, :body
|
172
|
+
|
173
|
+
has_many :comments
|
174
|
+
end
|
175
|
+
|
176
|
+
ActiveModel::Serializer.setup do |config|
|
177
|
+
config.default_key_type = nil
|
178
|
+
end
|
179
|
+
|
180
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
<p>Hello.</p>
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
module Serialization
|
5
|
+
class NamespacedSerializationTest < ActionController::TestCase
|
6
|
+
class TestNamespace::MyController < ActionController::Base
|
7
|
+
def render_profile_with_namespace
|
8
|
+
render json: Profile.new({ name: 'Name 1', description: 'Description 1'})
|
9
|
+
end
|
10
|
+
|
11
|
+
def render_profiles_with_namespace
|
12
|
+
render json: [Profile.new({ name: 'Name 1', description: 'Description 1'})]
|
13
|
+
end
|
14
|
+
|
15
|
+
def render_comment
|
16
|
+
render json: Comment.new(content: 'Comment 1')
|
17
|
+
end
|
18
|
+
|
19
|
+
def render_comments
|
20
|
+
render json: [Comment.new(content: 'Comment 1')]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
tests TestNamespace::MyController
|
25
|
+
|
26
|
+
def test_render_profile_with_namespace
|
27
|
+
get :render_profile_with_namespace
|
28
|
+
assert_serializer TestNamespace::ProfileSerializer
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_render_profiles_with_namespace
|
32
|
+
get :render_profiles_with_namespace
|
33
|
+
assert_serializer TestNamespace::ProfileSerializer
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_fallback_to_a_version_without_namespace
|
37
|
+
get :render_comment
|
38
|
+
assert_serializer CommentSerializer
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_array_fallback_to_a_version_without_namespace
|
42
|
+
get :render_comments
|
43
|
+
assert_serializer CommentSerializer
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class OptionNamespacedSerializationTest < ActionController::TestCase
|
48
|
+
class MyController < ActionController::Base
|
49
|
+
def default_serializer_options
|
50
|
+
{
|
51
|
+
namespace: TestNamespace
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def render_profile_with_namespace_option
|
56
|
+
render json: Profile.new({ name: 'Name 1', description: 'Description 1'})
|
57
|
+
end
|
58
|
+
|
59
|
+
def render_profiles_with_namespace_option
|
60
|
+
render json: [Profile.new({ name: 'Name 1', description: 'Description 1'})]
|
61
|
+
end
|
62
|
+
|
63
|
+
def render_comment
|
64
|
+
render json: Comment.new(content: 'Comment 1')
|
65
|
+
end
|
66
|
+
|
67
|
+
def render_comments
|
68
|
+
render json: [Comment.new(content: 'Comment 1')]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
tests MyController
|
73
|
+
|
74
|
+
def test_render_profile_with_namespace_option
|
75
|
+
get :render_profile_with_namespace_option
|
76
|
+
assert_serializer TestNamespace::ProfileSerializer
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_render_profiles_with_namespace_option
|
80
|
+
get :render_profiles_with_namespace_option
|
81
|
+
assert_serializer TestNamespace::ProfileSerializer
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_fallback_to_a_version_without_namespace
|
85
|
+
get :render_comment
|
86
|
+
assert_serializer CommentSerializer
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_array_fallback_to_a_version_without_namespace
|
90
|
+
get :render_comments
|
91
|
+
assert_serializer CommentSerializer
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|