active_model_serializers 0.10.0 → 0.10.7

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 (171) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +6 -5
  3. data/.travis.yml +30 -21
  4. data/CHANGELOG.md +172 -2
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +23 -4
  7. data/README.md +166 -28
  8. data/Rakefile +3 -32
  9. data/active_model_serializers.gemspec +22 -25
  10. data/appveyor.yml +10 -6
  11. data/bin/rubocop +38 -0
  12. data/docs/README.md +2 -1
  13. data/docs/general/adapters.md +35 -11
  14. data/docs/general/caching.md +7 -1
  15. data/docs/general/configuration_options.md +86 -1
  16. data/docs/general/deserialization.md +1 -1
  17. data/docs/general/fields.md +31 -0
  18. data/docs/general/getting_started.md +1 -1
  19. data/docs/general/logging.md +7 -0
  20. data/docs/general/rendering.md +63 -25
  21. data/docs/general/serializers.md +125 -14
  22. data/docs/howto/add_pagination_links.md +16 -17
  23. data/docs/howto/add_relationship_links.md +140 -0
  24. data/docs/howto/add_root_key.md +11 -0
  25. data/docs/howto/grape_integration.md +42 -0
  26. data/docs/howto/outside_controller_use.md +12 -4
  27. data/docs/howto/passing_arbitrary_options.md +2 -2
  28. data/docs/howto/serialize_poro.md +46 -5
  29. data/docs/howto/test.md +2 -0
  30. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  31. data/docs/integrations/ember-and-json-api.md +67 -32
  32. data/docs/jsonapi/schema.md +1 -1
  33. data/lib/action_controller/serialization.rb +13 -3
  34. data/lib/active_model/serializer/adapter/base.rb +2 -0
  35. data/lib/active_model/serializer/array_serializer.rb +8 -5
  36. data/lib/active_model/serializer/association.rb +62 -10
  37. data/lib/active_model/serializer/belongs_to_reflection.rb +4 -3
  38. data/lib/active_model/serializer/collection_serializer.rb +39 -13
  39. data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +82 -115
  40. data/lib/active_model/serializer/error_serializer.rb +11 -7
  41. data/lib/active_model/serializer/errors_serializer.rb +25 -20
  42. data/lib/active_model/serializer/has_many_reflection.rb +3 -3
  43. data/lib/active_model/serializer/has_one_reflection.rb +1 -4
  44. data/lib/active_model/serializer/lazy_association.rb +95 -0
  45. data/lib/active_model/serializer/lint.rb +134 -130
  46. data/lib/active_model/serializer/reflection.rb +127 -67
  47. data/lib/active_model/serializer/version.rb +1 -1
  48. data/lib/active_model/serializer.rb +297 -79
  49. data/lib/active_model_serializers/adapter/attributes.rb +3 -66
  50. data/lib/active_model_serializers/adapter/base.rb +39 -39
  51. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +2 -2
  52. data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
  53. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +47 -21
  54. data/lib/active_model_serializers/adapter/json_api/relationship.rb +75 -23
  55. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +39 -10
  56. data/lib/active_model_serializers/adapter/json_api.rb +71 -57
  57. data/lib/active_model_serializers/adapter.rb +6 -0
  58. data/lib/active_model_serializers/deprecate.rb +1 -2
  59. data/lib/active_model_serializers/deserialization.rb +2 -0
  60. data/lib/active_model_serializers/lookup_chain.rb +80 -0
  61. data/lib/active_model_serializers/model.rb +109 -28
  62. data/lib/active_model_serializers/railtie.rb +3 -1
  63. data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
  64. data/lib/active_model_serializers/serializable_resource.rb +6 -5
  65. data/lib/active_model_serializers/serialization_context.rb +10 -3
  66. data/lib/active_model_serializers/test/schema.rb +2 -2
  67. data/lib/active_model_serializers.rb +16 -1
  68. data/lib/generators/rails/resource_override.rb +1 -1
  69. data/lib/generators/rails/serializer_generator.rb +4 -4
  70. data/lib/grape/active_model_serializers.rb +7 -5
  71. data/lib/grape/formatters/active_model_serializers.rb +19 -2
  72. data/lib/grape/helpers/active_model_serializers.rb +1 -0
  73. data/lib/tasks/rubocop.rake +53 -0
  74. data/test/action_controller/adapter_selector_test.rb +14 -5
  75. data/test/action_controller/explicit_serializer_test.rb +5 -4
  76. data/test/action_controller/json/include_test.rb +106 -27
  77. data/test/action_controller/json_api/deserialization_test.rb +1 -1
  78. data/test/action_controller/json_api/errors_test.rb +8 -9
  79. data/test/action_controller/json_api/fields_test.rb +66 -0
  80. data/test/action_controller/json_api/linked_test.rb +29 -24
  81. data/test/action_controller/json_api/pagination_test.rb +31 -23
  82. data/test/action_controller/json_api/transform_test.rb +11 -3
  83. data/test/action_controller/lookup_proc_test.rb +49 -0
  84. data/test/action_controller/namespace_lookup_test.rb +232 -0
  85. data/test/action_controller/serialization_scope_name_test.rb +12 -6
  86. data/test/action_controller/serialization_test.rb +12 -9
  87. data/test/active_model_serializers/json_pointer_test.rb +15 -13
  88. data/test/active_model_serializers/model_test.rb +137 -4
  89. data/test/active_model_serializers/railtie_test_isolated.rb +12 -7
  90. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
  91. data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
  92. data/test/active_model_serializers/test/schema_test.rb +3 -2
  93. data/test/adapter/attributes_test.rb +40 -0
  94. data/test/adapter/json/collection_test.rb +14 -0
  95. data/test/adapter/json/has_many_test.rb +10 -2
  96. data/test/adapter/json/transform_test.rb +15 -15
  97. data/test/adapter/json_api/collection_test.rb +4 -3
  98. data/test/adapter/json_api/errors_test.rb +17 -19
  99. data/test/adapter/json_api/fields_test.rb +12 -3
  100. data/test/adapter/json_api/has_many_test.rb +49 -20
  101. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +213 -0
  102. data/test/adapter/json_api/json_api_test.rb +5 -7
  103. data/test/adapter/json_api/linked_test.rb +33 -12
  104. data/test/adapter/json_api/links_test.rb +4 -2
  105. data/test/adapter/json_api/pagination_links_test.rb +53 -13
  106. data/test/adapter/json_api/parse_test.rb +1 -1
  107. data/test/adapter/json_api/relationship_test.rb +309 -73
  108. data/test/adapter/json_api/resource_meta_test.rb +3 -3
  109. data/test/adapter/json_api/transform_test.rb +263 -253
  110. data/test/adapter/json_api/type_test.rb +168 -36
  111. data/test/adapter/json_test.rb +8 -7
  112. data/test/adapter/null_test.rb +1 -2
  113. data/test/adapter/polymorphic_test.rb +52 -5
  114. data/test/adapter_test.rb +1 -1
  115. data/test/benchmark/app.rb +1 -1
  116. data/test/benchmark/benchmarking_support.rb +1 -1
  117. data/test/benchmark/bm_active_record.rb +81 -0
  118. data/test/benchmark/bm_adapter.rb +38 -0
  119. data/test/benchmark/bm_caching.rb +16 -16
  120. data/test/benchmark/bm_lookup_chain.rb +83 -0
  121. data/test/benchmark/bm_transform.rb +21 -10
  122. data/test/benchmark/controllers.rb +16 -17
  123. data/test/benchmark/fixtures.rb +72 -72
  124. data/test/cache_test.rb +235 -69
  125. data/test/collection_serializer_test.rb +31 -14
  126. data/test/fixtures/active_record.rb +45 -10
  127. data/test/fixtures/poro.rb +124 -181
  128. data/test/generators/serializer_generator_test.rb +23 -5
  129. data/test/grape_test.rb +170 -56
  130. data/test/lint_test.rb +1 -1
  131. data/test/logger_test.rb +13 -11
  132. data/test/serializable_resource_test.rb +18 -22
  133. data/test/serializers/association_macros_test.rb +3 -2
  134. data/test/serializers/associations_test.rb +222 -49
  135. data/test/serializers/attribute_test.rb +5 -3
  136. data/test/serializers/attributes_test.rb +1 -1
  137. data/test/serializers/caching_configuration_test_isolated.rb +6 -6
  138. data/test/serializers/fieldset_test.rb +1 -1
  139. data/test/serializers/meta_test.rb +12 -6
  140. data/test/serializers/options_test.rb +17 -6
  141. data/test/serializers/read_attribute_for_serialization_test.rb +3 -3
  142. data/test/serializers/reflection_test.rb +427 -0
  143. data/test/serializers/root_test.rb +1 -1
  144. data/test/serializers/serialization_test.rb +2 -2
  145. data/test/serializers/serializer_for_test.rb +12 -10
  146. data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
  147. data/test/support/isolated_unit.rb +9 -4
  148. data/test/support/rails5_shims.rb +8 -2
  149. data/test/support/rails_app.rb +2 -9
  150. data/test/support/serialization_testing.rb +31 -5
  151. data/test/test_helper.rb +13 -0
  152. metadata +130 -71
  153. data/.rubocop_todo.yml +0 -167
  154. data/docs/ARCHITECTURE.md +0 -126
  155. data/lib/active_model/serializer/associations.rb +0 -100
  156. data/lib/active_model/serializer/attributes.rb +0 -82
  157. data/lib/active_model/serializer/collection_reflection.rb +0 -7
  158. data/lib/active_model/serializer/configuration.rb +0 -35
  159. data/lib/active_model/serializer/include_tree.rb +0 -111
  160. data/lib/active_model/serializer/links.rb +0 -35
  161. data/lib/active_model/serializer/meta.rb +0 -29
  162. data/lib/active_model/serializer/singular_reflection.rb +0 -7
  163. data/lib/active_model/serializer/type.rb +0 -25
  164. data/lib/active_model_serializers/key_transform.rb +0 -70
  165. data/test/active_model_serializers/key_transform_test.rb +0 -263
  166. data/test/adapter/json_api/has_many_embed_ids_test.rb +0 -43
  167. data/test/adapter/json_api/relationships_test.rb +0 -199
  168. data/test/adapter/json_api/resource_identifier_test.rb +0 -85
  169. data/test/include_tree/from_include_args_test.rb +0 -26
  170. data/test/include_tree/from_string_test.rb +0 -94
  171. data/test/include_tree/include_args_to_hash_test.rb +0 -64
data/test/lint_test.rb CHANGED
@@ -30,7 +30,7 @@ module ActiveModel
30
30
  def errors
31
31
  end
32
32
 
33
- def self.human_attribute_name(attr, options = {})
33
+ def self.human_attribute_name(_, _ = {})
34
34
  end
35
35
 
36
36
  def self.lookup_ancestors
data/test/logger_test.rb CHANGED
@@ -1,18 +1,20 @@
1
1
  require 'test_helper'
2
2
 
3
- class ActiveModelSerializers::LoggerTest < ActiveSupport::TestCase
4
- def test_logger_is_set_to_action_controller_logger_when_initializer_runs
5
- assert_equal $action_controller_logger, ActionController::Base.logger # rubocop:disable Style/GlobalVars
6
- end
3
+ module ActiveModelSerializers
4
+ class LoggerTest < ActiveSupport::TestCase
5
+ def test_logger_is_set_to_action_controller_logger_when_initializer_runs
6
+ assert_equal $action_controller_logger, ActionController::Base.logger # rubocop:disable Style/GlobalVars
7
+ end
7
8
 
8
- def test_logger_can_be_set
9
- original_logger = ActiveModelSerializers.logger
10
- logger = Logger.new(STDOUT)
9
+ def test_logger_can_be_set
10
+ original_logger = ActiveModelSerializers.logger
11
+ logger = Logger.new(STDOUT)
11
12
 
12
- ActiveModelSerializers.logger = logger
13
+ ActiveModelSerializers.logger = logger
13
14
 
14
- assert_equal ActiveModelSerializers.logger, logger
15
- ensure
16
- ActiveModelSerializers.logger = original_logger
15
+ assert_equal ActiveModelSerializers.logger, logger
16
+ ensure
17
+ ActiveModelSerializers.logger = original_logger
18
+ end
17
19
  end
18
20
  end
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  module ActiveModelSerializers
4
4
  class SerializableResourceTest < ActiveSupport::TestCase
5
5
  def setup
6
- @resource = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
6
+ @resource = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
7
7
  @serializer = ProfileSerializer.new(@resource)
8
8
  @adapter = ActiveModelSerializers::Adapter.create(@serializer)
9
9
  @serializable_resource = SerializableResource.new(@resource)
@@ -32,11 +32,11 @@ module ActiveModelSerializers
32
32
  end
33
33
 
34
34
  def test_use_adapter_with_adapter_option
35
- assert SerializableResource.new(@resource, { adapter: 'json' }).use_adapter?
35
+ assert SerializableResource.new(@resource, adapter: 'json').use_adapter?
36
36
  end
37
37
 
38
38
  def test_use_adapter_with_adapter_option_as_false
39
- refute SerializableResource.new(@resource, { adapter: false }).use_adapter?
39
+ refute SerializableResource.new(@resource, adapter: false).use_adapter?
40
40
  end
41
41
 
42
42
  class SerializableResourceErrorsTest < Minitest::Test
@@ -45,15 +45,13 @@ module ActiveModelSerializers
45
45
  resource = ModelWithErrors.new
46
46
  resource.errors.add(:name, 'must be awesome')
47
47
  serializable_resource = ActiveModelSerializers::SerializableResource.new(
48
- resource, {
49
- serializer: ActiveModel::Serializer::ErrorSerializer,
50
- adapter: :json_api
51
- })
52
- expected_response_document =
53
- { :errors =>
54
- [
55
- { :source => { :pointer => '/data/attributes/name' }, :detail => 'must be awesome' }
56
- ]
48
+ resource, serializer: ActiveModel::Serializer::ErrorSerializer,
49
+ adapter: :json_api
50
+ )
51
+ expected_response_document = {
52
+ errors: [
53
+ { source: { pointer: '/data/attributes/name' }, detail: 'must be awesome' }
54
+ ]
57
55
  }
58
56
  assert_equal serializable_resource.as_json(options), expected_response_document
59
57
  end
@@ -65,16 +63,14 @@ module ActiveModelSerializers
65
63
  resource.errors.add(:title, 'must be amazing')
66
64
  resources << ModelWithErrors.new
67
65
  serializable_resource = SerializableResource.new(
68
- resources, {
69
- serializer: ActiveModel::Serializer::ErrorsSerializer,
70
- each_serializer: ActiveModel::Serializer::ErrorSerializer,
71
- adapter: :json_api
72
- })
73
- expected_response_document =
74
- { :errors =>
75
- [
76
- { :source => { :pointer => '/data/attributes/title' }, :detail => 'must be amazing' }
77
- ]
66
+ resources, serializer: ActiveModel::Serializer::ErrorsSerializer,
67
+ each_serializer: ActiveModel::Serializer::ErrorSerializer,
68
+ adapter: :json_api
69
+ )
70
+ expected_response_document = {
71
+ errors: [
72
+ { source: { pointer: '/data/attributes/title' }, detail: 'must be amazing' }
73
+ ]
78
74
  }
79
75
  assert_equal serializable_resource.as_json(options), expected_response_document
80
76
  end
@@ -3,7 +3,8 @@ require 'test_helper'
3
3
  module ActiveModel
4
4
  class Serializer
5
5
  class AssociationMacrosTest < ActiveSupport::TestCase
6
- AuthorSummarySerializer = Class.new
6
+ class AuthorSummarySerializer < ActiveModel::Serializer; end
7
+
7
8
  class AssociationsTestSerializer < Serializer
8
9
  belongs_to :author, serializer: AuthorSummarySerializer
9
10
  has_many :comments
@@ -11,7 +12,7 @@ module ActiveModel
11
12
  end
12
13
 
13
14
  def before_setup
14
- @reflections = AssociationsTestSerializer._reflections
15
+ @reflections = AssociationsTestSerializer._reflections.values
15
16
  end
16
17
 
17
18
  def test_has_one_defines_reflection
@@ -1,16 +1,19 @@
1
1
  require 'test_helper'
2
-
3
2
  module ActiveModel
4
3
  class Serializer
5
4
  class AssociationsTest < ActiveSupport::TestCase
5
+ class ModelWithoutSerializer < ::Model
6
+ attributes :id, :name
7
+ end
8
+
6
9
  def setup
7
10
  @author = Author.new(name: 'Steve K.')
8
11
  @author.bio = nil
9
12
  @author.roles = []
10
- @blog = Blog.new({ name: 'AMS Blog' })
11
- @post = Post.new({ title: 'New Post', body: 'Body' })
12
- @tag = Tag.new({ name: '#hashtagged' })
13
- @comment = Comment.new({ id: 1, body: 'ZOMG A COMMENT' })
13
+ @blog = Blog.new(name: 'AMS Blog')
14
+ @post = Post.new(title: 'New Post', body: 'Body')
15
+ @tag = ModelWithoutSerializer.new(id: 'tagid', name: '#hashtagged')
16
+ @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
14
17
  @post.comments = [@comment]
15
18
  @post.tags = [@tag]
16
19
  @post.blog = @blog
@@ -19,7 +22,7 @@ module ActiveModel
19
22
  @post.author = @author
20
23
  @author.posts = [@post]
21
24
 
22
- @post_serializer = PostSerializer.new(@post, { custom_options: true })
25
+ @post_serializer = PostSerializer.new(@post, custom_options: true)
23
26
  @author_serializer = AuthorSerializer.new(@author)
24
27
  @comment_serializer = CommentSerializer.new(@comment)
25
28
  end
@@ -27,18 +30,17 @@ module ActiveModel
27
30
  def test_has_many_and_has_one
28
31
  @author_serializer.associations.each do |association|
29
32
  key = association.key
30
- serializer = association.serializer
31
- options = association.options
33
+ serializer = association.lazy_association.serializer
32
34
 
33
35
  case key
34
36
  when :posts
35
- assert_equal({ include_data: true }, options)
37
+ assert_equal true, association.include_data?
36
38
  assert_kind_of(ActiveModelSerializers.config.collection_serializer, serializer)
37
39
  when :bio
38
- assert_equal({ include_data: true }, options)
40
+ assert_equal true, association.include_data?
39
41
  assert_nil serializer
40
42
  when :roles
41
- assert_equal({ include_data: true }, options)
43
+ assert_equal true, association.include_data?
42
44
  assert_kind_of(ActiveModelSerializers.config.collection_serializer, serializer)
43
45
  else
44
46
  flunk "Unknown association: #{key}"
@@ -47,14 +49,17 @@ module ActiveModel
47
49
  end
48
50
 
49
51
  def test_has_many_with_no_serializer
50
- PostWithTagsSerializer.new(@post).associations.each do |association|
52
+ post_serializer_class = Class.new(ActiveModel::Serializer) do
53
+ attributes :id
54
+ has_many :tags
55
+ end
56
+ post_serializer_class.new(@post).associations.each do |association|
51
57
  key = association.key
52
- serializer = association.serializer
53
- options = association.options
58
+ serializer = association.lazy_association.serializer
54
59
 
55
60
  assert_equal :tags, key
56
61
  assert_nil serializer
57
- assert_equal [{ name: '#hashtagged' }].to_json, options[:virtual_value].to_json
62
+ assert_equal [{ id: 'tagid', name: '#hashtagged' }].to_json, association.virtual_value.to_json
58
63
  end
59
64
  end
60
65
 
@@ -63,13 +68,19 @@ module ActiveModel
63
68
  .associations
64
69
  .detect { |assoc| assoc.key == :comments }
65
70
 
66
- assert association.serializer.first.custom_options[:custom_options]
71
+ comment_serializer = association.lazy_association.serializer.first
72
+ class << comment_serializer
73
+ def custom_options
74
+ instance_options
75
+ end
76
+ end
77
+ assert comment_serializer.custom_options.fetch(:custom_options)
67
78
  end
68
79
 
69
80
  def test_belongs_to
70
81
  @comment_serializer.associations.each do |association|
71
82
  key = association.key
72
- serializer = association.serializer
83
+ serializer = association.lazy_association.serializer
73
84
 
74
85
  case key
75
86
  when :post
@@ -80,7 +91,7 @@ module ActiveModel
80
91
  flunk "Unknown association: #{key}"
81
92
  end
82
93
 
83
- assert_equal({ include_data: true }, association.options)
94
+ assert_equal true, association.include_data?
84
95
  end
85
96
  end
86
97
 
@@ -104,13 +115,13 @@ module ActiveModel
104
115
  end
105
116
 
106
117
  assert(
107
- PostSerializer._reflections.all? do |reflection|
108
- inherited_klass._reflections.include?(reflection)
118
+ PostSerializer._reflections.values.all? do |reflection|
119
+ inherited_klass._reflections.values.include?(reflection)
109
120
  end
110
121
  )
111
122
 
112
123
  assert(
113
- inherited_klass._reflections.any? do |reflection|
124
+ inherited_klass._reflections.values.any? do |reflection|
114
125
  reflection.name == :top_comments
115
126
  end
116
127
  )
@@ -126,6 +137,78 @@ module ActiveModel
126
137
  assert expected_association_keys.include? :site
127
138
  end
128
139
 
140
+ class BelongsToBlogModel < ::Model
141
+ attributes :id, :title
142
+ associations :blog
143
+ end
144
+ class BelongsToBlogModelSerializer < ActiveModel::Serializer
145
+ type :posts
146
+ belongs_to :blog
147
+ end
148
+
149
+ def test_belongs_to_doesnt_load_record
150
+ attributes = { id: 1, title: 'Belongs to Blog', blog: Blog.new(id: 5) }
151
+ post = BelongsToBlogModel.new(attributes)
152
+ class << post
153
+ def blog
154
+ fail 'should use blog_id'
155
+ end
156
+
157
+ def blog_id
158
+ 5
159
+ end
160
+ end
161
+
162
+ actual =
163
+ begin
164
+ original_option = BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship
165
+ BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
166
+ serializable(post, adapter: :json_api, serializer: BelongsToBlogModelSerializer).as_json
167
+ ensure
168
+ BelongsToBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = original_option
169
+ end
170
+ expected = { data: { id: '1', type: 'posts', relationships: { blog: { data: { id: '5', type: 'blogs' } } } } }
171
+
172
+ assert_equal expected, actual
173
+ end
174
+
175
+ class ExternalBlog < Blog
176
+ attributes :external_id
177
+ end
178
+ class BelongsToExternalBlogModel < ::Model
179
+ attributes :id, :title, :external_blog_id
180
+ associations :external_blog
181
+ end
182
+ class BelongsToExternalBlogModelSerializer < ActiveModel::Serializer
183
+ type :posts
184
+ belongs_to :external_blog
185
+
186
+ def external_blog_id
187
+ object.external_blog.external_id
188
+ end
189
+ end
190
+
191
+ def test_belongs_to_allows_id_overwriting
192
+ attributes = {
193
+ id: 1,
194
+ title: 'Title',
195
+ external_blog: ExternalBlog.new(id: 5, external_id: 6)
196
+ }
197
+ post = BelongsToExternalBlogModel.new(attributes)
198
+
199
+ actual =
200
+ begin
201
+ original_option = BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship
202
+ BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = true
203
+ serializable(post, adapter: :json_api, serializer: BelongsToExternalBlogModelSerializer).as_json
204
+ ensure
205
+ BelongsToExternalBlogModelSerializer.config.jsonapi_use_foreign_key_on_belongs_to_relationship = original_option
206
+ end
207
+ expected = { data: { id: '1', type: 'posts', relationships: { :'external-blog' => { data: { id: '6', type: 'external-blogs' } } } } }
208
+
209
+ assert_equal expected, actual
210
+ end
211
+
129
212
  class InlineAssociationTestPostSerializer < ActiveModel::Serializer
130
213
  has_many :comments
131
214
  has_many :comments, key: :last_comments do
@@ -143,12 +226,12 @@ module ActiveModel
143
226
  )
144
227
  actual = serializable(post, adapter: :attributes, serializer: InlineAssociationTestPostSerializer).as_json
145
228
  expected = {
146
- :comments => [
147
- { :id => 1, :contents => 'first comment' },
148
- { :id => 2, :contents => 'last comment' }
229
+ comments: [
230
+ { id: 1, contents: 'first comment' },
231
+ { id: 2, contents: 'last comment' }
149
232
  ],
150
- :last_comments => [
151
- { :id => 2, :contents => 'last comment' }
233
+ last_comments: [
234
+ { id: 2, contents: 'last comment' }
152
235
  ]
153
236
  }
154
237
 
@@ -160,18 +243,20 @@ module ActiveModel
160
243
 
161
244
  class NamespacedResourcesTest < ActiveSupport::TestCase
162
245
  class ResourceNamespace
163
- Post = Class.new(::Model)
164
- Comment = Class.new(::Model)
165
- Author = Class.new(::Model)
166
- Description = Class.new(::Model)
246
+ class Post < ::Model
247
+ associations :comments, :author, :description
248
+ end
249
+ class Comment < ::Model; end
250
+ class Author < ::Model; end
251
+ class Description < ::Model; end
167
252
  class PostSerializer < ActiveModel::Serializer
168
253
  has_many :comments
169
254
  belongs_to :author
170
255
  has_one :description
171
256
  end
172
- CommentSerializer = Class.new(ActiveModel::Serializer)
173
- AuthorSerializer = Class.new(ActiveModel::Serializer)
174
- DescriptionSerializer = Class.new(ActiveModel::Serializer)
257
+ class CommentSerializer < ActiveModel::Serializer; end
258
+ class AuthorSerializer < ActiveModel::Serializer; end
259
+ class DescriptionSerializer < ActiveModel::Serializer; end
175
260
  end
176
261
 
177
262
  def setup
@@ -188,11 +273,11 @@ module ActiveModel
188
273
  @post_serializer.associations.each do |association|
189
274
  case association.key
190
275
  when :comments
191
- assert_instance_of(ResourceNamespace::CommentSerializer, association.serializer.first)
276
+ assert_instance_of(ResourceNamespace::CommentSerializer, association.lazy_association.serializer.first)
192
277
  when :author
193
- assert_instance_of(ResourceNamespace::AuthorSerializer, association.serializer)
278
+ assert_instance_of(ResourceNamespace::AuthorSerializer, association.lazy_association.serializer)
194
279
  when :description
195
- assert_instance_of(ResourceNamespace::DescriptionSerializer, association.serializer)
280
+ assert_instance_of(ResourceNamespace::DescriptionSerializer, association.lazy_association.serializer)
196
281
  else
197
282
  flunk "Unknown association: #{key}"
198
283
  end
@@ -201,17 +286,19 @@ module ActiveModel
201
286
  end
202
287
 
203
288
  class NestedSerializersTest < ActiveSupport::TestCase
204
- Post = Class.new(::Model)
205
- Comment = Class.new(::Model)
206
- Author = Class.new(::Model)
207
- Description = Class.new(::Model)
289
+ class Post < ::Model
290
+ associations :comments, :author, :description
291
+ end
292
+ class Comment < ::Model; end
293
+ class Author < ::Model; end
294
+ class Description < ::Model; end
208
295
  class PostSerializer < ActiveModel::Serializer
209
296
  has_many :comments
210
- CommentSerializer = Class.new(ActiveModel::Serializer)
297
+ class CommentSerializer < ActiveModel::Serializer; end
211
298
  belongs_to :author
212
- AuthorSerializer = Class.new(ActiveModel::Serializer)
299
+ class AuthorSerializer < ActiveModel::Serializer; end
213
300
  has_one :description
214
- DescriptionSerializer = Class.new(ActiveModel::Serializer)
301
+ class DescriptionSerializer < ActiveModel::Serializer; end
215
302
  end
216
303
 
217
304
  def setup
@@ -228,11 +315,11 @@ module ActiveModel
228
315
  @post_serializer.associations.each do |association|
229
316
  case association.key
230
317
  when :comments
231
- assert_instance_of(PostSerializer::CommentSerializer, association.serializer.first)
318
+ assert_instance_of(PostSerializer::CommentSerializer, association.lazy_association.serializer.first)
232
319
  when :author
233
- assert_instance_of(PostSerializer::AuthorSerializer, association.serializer)
320
+ assert_instance_of(PostSerializer::AuthorSerializer, association.lazy_association.serializer)
234
321
  when :description
235
- assert_instance_of(PostSerializer::DescriptionSerializer, association.serializer)
322
+ assert_instance_of(PostSerializer::DescriptionSerializer, association.lazy_association.serializer)
236
323
  else
237
324
  flunk "Unknown association: #{key}"
238
325
  end
@@ -241,7 +328,10 @@ module ActiveModel
241
328
 
242
329
  # rubocop:disable Metrics/AbcSize
243
330
  def test_conditional_associations
244
- model = ::Model.new(true: true, false: false)
331
+ model = Class.new(::Model) do
332
+ attributes :true, :false
333
+ associations :something
334
+ end.new(true: true, false: false)
245
335
 
246
336
  scenarios = [
247
337
  { options: { if: :true }, included: true },
@@ -264,7 +354,7 @@ module ActiveModel
264
354
 
265
355
  scenarios.each do |s|
266
356
  serializer = Class.new(ActiveModel::Serializer) do
267
- belongs_to :association, s[:options]
357
+ belongs_to :something, s[:options]
268
358
 
269
359
  def true
270
360
  true
@@ -276,7 +366,7 @@ module ActiveModel
276
366
  end
277
367
 
278
368
  hash = serializable(model, serializer: serializer).serializable_hash
279
- assert_equal(s[:included], hash.key?(:association), "Error with #{s[:options]}")
369
+ assert_equal(s[:included], hash.key?(:something), "Error with #{s[:options]}")
280
370
  end
281
371
  end
282
372
 
@@ -290,6 +380,89 @@ module ActiveModel
290
380
  assert_match(/:if should be a Symbol, String or Proc/, exception.message)
291
381
  end
292
382
  end
383
+
384
+ class InheritedSerializerTest < ActiveSupport::TestCase
385
+ class PostSerializer < ActiveModel::Serializer
386
+ belongs_to :author
387
+ has_many :comments
388
+ belongs_to :blog
389
+ end
390
+
391
+ class InheritedPostSerializer < PostSerializer
392
+ belongs_to :author, polymorphic: true
393
+ has_many :comments, key: :reviews
394
+ end
395
+
396
+ class AuthorSerializer < ActiveModel::Serializer
397
+ has_many :posts
398
+ has_many :roles
399
+ has_one :bio
400
+ end
401
+
402
+ class InheritedAuthorSerializer < AuthorSerializer
403
+ has_many :roles, polymorphic: true
404
+ has_one :bio, polymorphic: true
405
+ end
406
+
407
+ def setup
408
+ @author = Author.new(name: 'Steve K.')
409
+ @post = Post.new(title: 'New Post', body: 'Body')
410
+ @post_serializer = PostSerializer.new(@post)
411
+ @author_serializer = AuthorSerializer.new(@author)
412
+ @inherited_post_serializer = InheritedPostSerializer.new(@post)
413
+ @inherited_author_serializer = InheritedAuthorSerializer.new(@author)
414
+ @author_associations = @author_serializer.associations.to_a.sort_by(&:name)
415
+ @inherited_author_associations = @inherited_author_serializer.associations.to_a.sort_by(&:name)
416
+ @post_associations = @post_serializer.associations.to_a
417
+ @inherited_post_associations = @inherited_post_serializer.associations.to_a
418
+ end
419
+
420
+ test 'an author serializer must have [posts,roles,bio] associations' do
421
+ expected = [:posts, :roles, :bio].sort
422
+ result = @author_serializer.associations.map(&:name).sort
423
+ assert_equal(result, expected)
424
+ end
425
+
426
+ test 'a post serializer must have [author,comments,blog] associations' do
427
+ expected = [:author, :comments, :blog].sort
428
+ result = @post_serializer.associations.map(&:name).sort
429
+ assert_equal(result, expected)
430
+ end
431
+
432
+ test 'a serializer inheriting from another serializer can redefine has_many and has_one associations' do
433
+ expected = [:roles, :bio].sort
434
+ result = (@inherited_author_associations.map(&:reflection) - @author_associations.map(&:reflection)).map(&:name)
435
+ assert_equal(result, expected)
436
+ assert_equal [true, false, true], @inherited_author_associations.map(&:polymorphic?)
437
+ assert_equal [false, false, false], @author_associations.map(&:polymorphic?)
438
+ end
439
+
440
+ test 'a serializer inheriting from another serializer can redefine belongs_to associations' do
441
+ assert_equal [:author, :comments, :blog], @post_associations.map(&:name)
442
+ assert_equal [:author, :comments, :blog, :comments], @inherited_post_associations.map(&:name)
443
+
444
+ refute @post_associations.detect { |assoc| assoc.name == :author }.polymorphic?
445
+ assert @inherited_post_associations.detect { |assoc| assoc.name == :author }.polymorphic?
446
+
447
+ refute @post_associations.detect { |assoc| assoc.name == :comments }.key?
448
+ original_comment_assoc, new_comments_assoc = @inherited_post_associations.select { |assoc| assoc.name == :comments }
449
+ refute original_comment_assoc.key?
450
+ assert_equal :reviews, new_comments_assoc.key
451
+
452
+ original_blog = @post_associations.detect { |assoc| assoc.name == :blog }
453
+ inherited_blog = @inherited_post_associations.detect { |assoc| assoc.name == :blog }
454
+ original_parent_serializer = original_blog.lazy_association.association_options.delete(:parent_serializer)
455
+ inherited_parent_serializer = inherited_blog.lazy_association.association_options.delete(:parent_serializer)
456
+ assert_equal PostSerializer, original_parent_serializer.class
457
+ assert_equal InheritedPostSerializer, inherited_parent_serializer.class
458
+ end
459
+
460
+ test 'a serializer inheriting from another serializer can have an additional association with the same name but with different key' do
461
+ expected = [:author, :comments, :blog, :reviews].sort
462
+ result = @inherited_post_serializer.associations.map(&:key).sort
463
+ assert_equal(result, expected)
464
+ end
465
+ end
293
466
  end
294
467
  end
295
468
  end
@@ -22,7 +22,7 @@ module ActiveModel
22
22
  inherited_klass = Class.new(AlternateBlogSerializer)
23
23
  blog_serializer = inherited_klass.new(@blog)
24
24
  adapter = ActiveModelSerializers::Adapter::Attributes.new(blog_serializer)
25
- assert_equal({ :id => 1, :title => 'AMS Hints' }, adapter.serializable_hash)
25
+ assert_equal({ id: 1, title: 'AMS Hints' }, adapter.serializable_hash)
26
26
  end
27
27
 
28
28
  def test_multiple_calls_with_the_same_attribute
@@ -81,7 +81,7 @@ module ActiveModel
81
81
  assert_equal('custom', hash[:blog][:id])
82
82
  end
83
83
 
84
- PostWithVirtualAttribute = Class.new(::Model)
84
+ class PostWithVirtualAttribute < ::Model; attributes :first_name, :last_name end
85
85
  class PostWithVirtualAttributeSerializer < ActiveModel::Serializer
86
86
  attribute :name do
87
87
  "#{object.first_name} #{object.last_name}"
@@ -98,7 +98,9 @@ module ActiveModel
98
98
 
99
99
  # rubocop:disable Metrics/AbcSize
100
100
  def test_conditional_associations
101
- model = ::Model.new(true: true, false: false)
101
+ model = Class.new(::Model) do
102
+ attributes :true, :false, :attribute
103
+ end.new(true: true, false: false)
102
104
 
103
105
  scenarios = [
104
106
  { options: { if: :true }, included: true },
@@ -4,7 +4,7 @@ module ActiveModel
4
4
  class Serializer
5
5
  class AttributesTest < ActiveSupport::TestCase
6
6
  def setup
7
- @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
7
+ @profile = Profile.new(name: 'Name 1', description: 'Description 1', comments: 'Comments 1')
8
8
  @profile_serializer = ProfileSerializer.new(@profile)
9
9
  @comment = Comment.new(id: 1, body: 'ZOMG!!', date: '2015')
10
10
  @serializer_klass = Class.new(CommentSerializer)
@@ -69,9 +69,9 @@ class CachingConfigurationTest < ActiveSupport::TestCase
69
69
  end
70
70
 
71
71
  test 'the non-cached serializer cache_store is nil' do
72
- assert_equal nil, @non_cached_serializer._cache
73
- assert_equal nil, @non_cached_serializer.cache_store
74
- assert_equal nil, @non_cached_serializer._cache
72
+ assert_nil @non_cached_serializer._cache
73
+ assert_nil @non_cached_serializer.cache_store
74
+ assert_nil @non_cached_serializer._cache
75
75
  end
76
76
 
77
77
  test 'the non-cached serializer does not have cache_enabled?' do
@@ -136,9 +136,9 @@ class CachingConfigurationTest < ActiveSupport::TestCase
136
136
  end
137
137
 
138
138
  test 'the non-cached serializer cache_store is nil' do
139
- assert_equal nil, @non_cached_serializer._cache
140
- assert_equal nil, @non_cached_serializer.cache_store
141
- assert_equal nil, @non_cached_serializer._cache
139
+ assert_nil @non_cached_serializer._cache
140
+ assert_nil @non_cached_serializer.cache_store
141
+ assert_nil @non_cached_serializer._cache
142
142
  end
143
143
 
144
144
  test 'the non-cached serializer does not have cache_enabled?' do
@@ -5,7 +5,7 @@ module ActiveModel
5
5
  class FieldsetTest < ActiveSupport::TestCase
6
6
  def test_fieldset_with_hash
7
7
  fieldset = ActiveModel::Serializer::Fieldset.new('post' => %w(id title), 'comment' => ['body'])
8
- expected = { :post => [:id, :title], :comment => [:body] }
8
+ expected = { post: [:id, :title], comment: [:body] }
9
9
 
10
10
  assert_equal(expected, fieldset.fields)
11
11
  end