cheap_ams 0.10.0.rc2

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 (97) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.travis.yml +26 -0
  4. data/CHANGELOG.md +13 -0
  5. data/CONTRIBUTING.md +31 -0
  6. data/Gemfile +35 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +348 -0
  9. data/Rakefile +12 -0
  10. data/appveyor.yml +25 -0
  11. data/cheap_ams.gemspec +49 -0
  12. data/docs/README.md +27 -0
  13. data/docs/general/adapters.md +51 -0
  14. data/docs/general/getting_started.md +73 -0
  15. data/docs/howto/add_pagination_links.md +112 -0
  16. data/docs/howto/add_root_key.md +51 -0
  17. data/lib/action_controller/serialization.rb +62 -0
  18. data/lib/active_model/serializable_resource.rb +84 -0
  19. data/lib/active_model/serializer/adapter/flatten_json.rb +19 -0
  20. data/lib/active_model/serializer/adapter/fragment_cache.rb +82 -0
  21. data/lib/active_model/serializer/adapter/json/fragment_cache.rb +16 -0
  22. data/lib/active_model/serializer/adapter/json.rb +53 -0
  23. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +24 -0
  24. data/lib/active_model/serializer/adapter/json_api/pagination_links.rb +58 -0
  25. data/lib/active_model/serializer/adapter/json_api.rb +183 -0
  26. data/lib/active_model/serializer/adapter/null.rb +11 -0
  27. data/lib/active_model/serializer/adapter.rb +98 -0
  28. data/lib/active_model/serializer/array_serializer.rb +35 -0
  29. data/lib/active_model/serializer/association.rb +21 -0
  30. data/lib/active_model/serializer/associations.rb +97 -0
  31. data/lib/active_model/serializer/belongs_to_reflection.rb +10 -0
  32. data/lib/active_model/serializer/collection_reflection.rb +7 -0
  33. data/lib/active_model/serializer/configuration.rb +14 -0
  34. data/lib/active_model/serializer/fieldset.rb +42 -0
  35. data/lib/active_model/serializer/has_many_reflection.rb +10 -0
  36. data/lib/active_model/serializer/has_one_reflection.rb +10 -0
  37. data/lib/active_model/serializer/lint.rb +131 -0
  38. data/lib/active_model/serializer/railtie.rb +9 -0
  39. data/lib/active_model/serializer/reflection.rb +74 -0
  40. data/lib/active_model/serializer/singular_reflection.rb +7 -0
  41. data/lib/active_model/serializer/version.rb +5 -0
  42. data/lib/active_model/serializer.rb +205 -0
  43. data/lib/active_model_serializers.rb +29 -0
  44. data/lib/generators/serializer/USAGE +6 -0
  45. data/lib/generators/serializer/resource_override.rb +12 -0
  46. data/lib/generators/serializer/serializer_generator.rb +37 -0
  47. data/lib/generators/serializer/templates/serializer.rb +8 -0
  48. data/test/action_controller/adapter_selector_test.rb +53 -0
  49. data/test/action_controller/explicit_serializer_test.rb +134 -0
  50. data/test/action_controller/json_api/linked_test.rb +180 -0
  51. data/test/action_controller/json_api/pagination_test.rb +116 -0
  52. data/test/action_controller/serialization_scope_name_test.rb +67 -0
  53. data/test/action_controller/serialization_test.rb +426 -0
  54. data/test/adapter/fragment_cache_test.rb +37 -0
  55. data/test/adapter/json/belongs_to_test.rb +47 -0
  56. data/test/adapter/json/collection_test.rb +82 -0
  57. data/test/adapter/json/has_many_test.rb +47 -0
  58. data/test/adapter/json_api/belongs_to_test.rb +157 -0
  59. data/test/adapter/json_api/collection_test.rb +96 -0
  60. data/test/adapter/json_api/has_many_embed_ids_test.rb +45 -0
  61. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
  62. data/test/adapter/json_api/has_many_test.rb +145 -0
  63. data/test/adapter/json_api/has_one_test.rb +81 -0
  64. data/test/adapter/json_api/json_api_test.rb +38 -0
  65. data/test/adapter/json_api/linked_test.rb +283 -0
  66. data/test/adapter/json_api/pagination_links_test.rb +115 -0
  67. data/test/adapter/json_api/resource_type_config_test.rb +59 -0
  68. data/test/adapter/json_test.rb +47 -0
  69. data/test/adapter/null_test.rb +25 -0
  70. data/test/adapter_test.rb +52 -0
  71. data/test/array_serializer_test.rb +97 -0
  72. data/test/capture_warnings.rb +57 -0
  73. data/test/fixtures/active_record.rb +57 -0
  74. data/test/fixtures/poro.rb +266 -0
  75. data/test/generators/scaffold_controller_generator_test.rb +24 -0
  76. data/test/generators/serializer_generator_test.rb +56 -0
  77. data/test/lint_test.rb +44 -0
  78. data/test/poro_test.rb +9 -0
  79. data/test/serializable_resource_test.rb +27 -0
  80. data/test/serializers/adapter_for_test.rb +50 -0
  81. data/test/serializers/association_macros_test.rb +36 -0
  82. data/test/serializers/associations_test.rb +150 -0
  83. data/test/serializers/attribute_test.rb +62 -0
  84. data/test/serializers/attributes_test.rb +63 -0
  85. data/test/serializers/cache_test.rb +164 -0
  86. data/test/serializers/configuration_test.rb +15 -0
  87. data/test/serializers/fieldset_test.rb +26 -0
  88. data/test/serializers/meta_test.rb +121 -0
  89. data/test/serializers/options_test.rb +21 -0
  90. data/test/serializers/root_test.rb +23 -0
  91. data/test/serializers/serializer_for_test.rb +65 -0
  92. data/test/serializers/urls_test.rb +26 -0
  93. data/test/support/rails_app.rb +21 -0
  94. data/test/support/stream_capture.rb +49 -0
  95. data/test/support/test_case.rb +5 -0
  96. data/test/test_helper.rb +41 -0
  97. metadata +287 -0
@@ -0,0 +1,74 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ # Holds all the meta-data about an association as it was specified in the
4
+ # ActiveModel::Serializer class.
5
+ #
6
+ # @example
7
+ # class PostSerializer < ActiveModel::Serializer
8
+ # has_one :author, serializer: AuthorSerializer
9
+ # has_many :comments
10
+ # end
11
+ #
12
+ # PostSerializer._reflections #=>
13
+ # # [
14
+ # # HasOneReflection.new(:author, serializer: AuthorSerializer),
15
+ # # HasManyReflection.new(:comments)
16
+ # # ]
17
+ #
18
+ # So you can inspect reflections in your Adapters.
19
+ #
20
+ Reflection = Struct.new(:name, :options) do
21
+ # Build association. This method is used internally to
22
+ # build serializer's association by its reflection.
23
+ #
24
+ # @param [Serializer] subject is a parent serializer for given association
25
+ # @param [Hash{Symbol => Object}] parent_serializer_options
26
+ #
27
+ # @example
28
+ # # Given the following serializer defined:
29
+ # class PostSerializer < ActiveModel::Serializer
30
+ # has_many :comments, serializer: CommentSummarySerializer
31
+ # end
32
+ #
33
+ # # Then you instantiate your serializer
34
+ # post_serializer = PostSerializer.new(post, foo: 'bar') #
35
+ # # to build association for comments you need to get reflection
36
+ # comments_reflection = PostSerializer._reflections.detect { |r| r.name == :comments }
37
+ # # and #build_association
38
+ # comments_reflection.build_association(post_serializer, foo: 'bar')
39
+ #
40
+ # @api private
41
+ #
42
+ def build_association(subject, parent_serializer_options)
43
+ association_value = subject.send(name)
44
+ reflection_options = options.dup
45
+ serializer_class = ActiveModel::Serializer.serializer_for(association_value, reflection_options)
46
+
47
+ if serializer_class
48
+ begin
49
+ serializer = serializer_class.new(
50
+ association_value,
51
+ serializer_options(parent_serializer_options, reflection_options)
52
+ )
53
+ rescue ActiveModel::Serializer::ArraySerializer::NoSerializerError
54
+ reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
55
+ end
56
+ elsif !association_value.nil? && !association_value.instance_of?(Object)
57
+ reflection_options[:virtual_value] = association_value
58
+ end
59
+
60
+ Association.new(name, serializer, reflection_options)
61
+ end
62
+
63
+ private
64
+
65
+ def serializer_options(parent_serializer_options, reflection_options)
66
+ serializer = reflection_options.fetch(:serializer, nil)
67
+
68
+ serializer_options = parent_serializer_options.except(:serializer)
69
+ serializer_options[:serializer] = serializer if serializer
70
+ serializer_options
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,7 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ # @api private
4
+ class SingularReflection < Reflection
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ VERSION = "0.10.0.rc2"
4
+ end
5
+ end
@@ -0,0 +1,205 @@
1
+ require 'thread_safe'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :Configuration
8
+ autoload :ArraySerializer
9
+ autoload :Adapter
10
+ autoload :Lint
11
+ autoload :Associations
12
+ autoload :Fieldset
13
+ include Configuration
14
+ include Associations
15
+
16
+
17
+ # Matches
18
+ # "c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb:1:in `<top (required)>'"
19
+ # AND
20
+ # "/c/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb:1:in `<top (required)>'"
21
+ # AS
22
+ # c/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb
23
+ CALLER_FILE = /
24
+ \A # start of string
25
+ \S+ # one or more non-spaces
26
+ (?= # stop previous match when
27
+ :\d+ # a colon is followed by one or more digits
28
+ :in # followed by a colon followed by in
29
+ )
30
+ /x
31
+
32
+ class << self
33
+ attr_accessor :_attributes
34
+ attr_accessor :_attributes_keys
35
+ attr_accessor :_urls
36
+ attr_accessor :_cache
37
+ attr_accessor :_fragmented
38
+ attr_accessor :_cache_key
39
+ attr_accessor :_cache_only
40
+ attr_accessor :_cache_except
41
+ attr_accessor :_cache_options
42
+ attr_accessor :_cache_digest
43
+ end
44
+
45
+ def self.inherited(base)
46
+ base._attributes = self._attributes.try(:dup) || []
47
+ base._attributes_keys = self._attributes_keys.try(:dup) || {}
48
+ base._urls = []
49
+ base._cache_digest = digest_caller_file(caller.first)
50
+ super
51
+ end
52
+
53
+ def self.attributes(*attrs)
54
+ attrs = attrs.first if attrs.first.class == Array
55
+ @_attributes.concat attrs
56
+ @_attributes.uniq!
57
+
58
+ attrs.each do |attr|
59
+ define_method attr do
60
+ object && object.read_attribute_for_serialization(attr)
61
+ end unless method_defined?(attr) || _fragmented.respond_to?(attr)
62
+ end
63
+ end
64
+
65
+ def self.attribute(attr, options = {})
66
+ key = options.fetch(:key, attr)
67
+ @_attributes_keys[attr] = { key: key } if key != attr
68
+ @_attributes << key unless @_attributes.include?(key)
69
+
70
+ ActiveModelSerializers.silence_warnings do
71
+ define_method key do
72
+ object.read_attribute_for_serialization(attr)
73
+ end unless (key != :id && method_defined?(key)) || _fragmented.respond_to?(attr)
74
+ end
75
+ end
76
+
77
+ def self.fragmented(serializer)
78
+ @_fragmented = serializer
79
+ end
80
+
81
+ # Enables a serializer to be automatically cached
82
+ def self.cache(options = {})
83
+ @_cache = ActionController::Base.cache_store if Rails.configuration.action_controller.perform_caching
84
+ @_cache_key = options.delete(:key)
85
+ @_cache_only = options.delete(:only)
86
+ @_cache_except = options.delete(:except)
87
+ @_cache_options = (options.empty?) ? nil : options
88
+ end
89
+
90
+ def self.url(attr)
91
+ @_urls.push attr
92
+ end
93
+
94
+ def self.urls(*attrs)
95
+ @_urls.concat attrs
96
+ end
97
+
98
+ def self.serializer_for(resource, options = {})
99
+ if resource.respond_to?(:serializer_class)
100
+ resource.serializer_class
101
+ elsif resource.respond_to?(:to_ary)
102
+ config.array_serializer
103
+ else
104
+ options.fetch(:serializer, get_serializer_for(resource.class))
105
+ end
106
+ end
107
+
108
+ def self.adapter
109
+ adapter_class = case config.adapter
110
+ when Symbol
111
+ ActiveModel::Serializer::Adapter.adapter_class(config.adapter)
112
+ when Class
113
+ config.adapter
114
+ end
115
+ unless adapter_class
116
+ valid_adapters = Adapter.constants.map { |klass| ":#{klass.to_s.downcase}" }
117
+ raise ArgumentError, "Unknown adapter: #{config.adapter}. Valid adapters are: #{valid_adapters}"
118
+ end
119
+
120
+ adapter_class
121
+ end
122
+
123
+ def self.root_name
124
+ name.demodulize.underscore.sub(/_serializer$/, '') if name
125
+ end
126
+
127
+ attr_accessor :object, :root, :meta, :meta_key, :scope
128
+
129
+ def initialize(object, options = {})
130
+ @object = object
131
+ @options = options
132
+ @root = options[:root]
133
+ @meta = options[:meta]
134
+ @meta_key = options[:meta_key]
135
+ @scope = options[:scope]
136
+
137
+ scope_name = options[:scope_name]
138
+ if scope_name && !respond_to?(scope_name)
139
+ self.class.class_eval do
140
+ define_method scope_name, lambda { scope }
141
+ end
142
+ end
143
+ end
144
+
145
+ def json_key
146
+ @root || object.class.model_name.to_s.underscore
147
+ end
148
+
149
+ def id
150
+ object.id if object
151
+ end
152
+
153
+ def json_api_type
154
+ if config.jsonapi_resource_type == :plural
155
+ object.class.model_name.plural
156
+ else
157
+ object.class.model_name.singular
158
+ end
159
+ end
160
+
161
+ def attributes(options = {})
162
+ attributes =
163
+ if options[:fields]
164
+ self.class._attributes & options[:fields]
165
+ else
166
+ self.class._attributes.dup
167
+ end
168
+
169
+ attributes += options[:required_fields] if options[:required_fields]
170
+
171
+ attributes.each_with_object({}) do |name, hash|
172
+ unless self.class._fragmented
173
+ hash[name] = send(name)
174
+ else
175
+ hash[name] = self.class._fragmented.public_send(name)
176
+ end
177
+ end
178
+ end
179
+
180
+ def self.serializers_cache
181
+ @serializers_cache ||= ThreadSafe::Cache.new
182
+ end
183
+
184
+ def self.digest_caller_file(caller_line)
185
+ serializer_file_path = caller_line[CALLER_FILE]
186
+ serializer_file_contents = IO.read(serializer_file_path)
187
+ Digest::MD5.hexdigest(serializer_file_contents)
188
+ end
189
+
190
+ attr_reader :options
191
+
192
+ def self.get_serializer_for(klass)
193
+ serializers_cache.fetch_or_store(klass) do
194
+ serializer_class_name = "#{klass.name}Serializer"
195
+ serializer_class = serializer_class_name.safe_constantize
196
+
197
+ if serializer_class
198
+ serializer_class
199
+ elsif klass.superclass
200
+ get_serializer_for(klass.superclass)
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,29 @@
1
+ module ActiveModelSerializers
2
+ module_function
3
+
4
+ def silence_warnings
5
+ verbose = $VERBOSE
6
+ $VERBOSE = nil
7
+ yield
8
+ ensure
9
+ $VERBOSE = verbose
10
+ end
11
+
12
+ end
13
+
14
+ require 'active_model'
15
+ require 'action_controller'
16
+
17
+ require 'active_model/serializer'
18
+ require 'active_model/serializable_resource'
19
+ require 'active_model/serializer/version'
20
+
21
+ require 'action_controller/serialization'
22
+ ActiveSupport.on_load(:action_controller) do
23
+ include ::ActionController::Serialization
24
+ ActionDispatch::Reloader.to_prepare do
25
+ ActiveModel::Serializer.serializers_cache.clear
26
+ end
27
+ end
28
+
29
+ require 'active_model/serializer/railtie'
@@ -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,12 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/rails/resource/resource_generator'
3
+
4
+ module Rails
5
+ module Generators
6
+ class ResourceGenerator
7
+ def add_serializer
8
+ invoke 'serializer'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -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
+ <% association_names.each do |attribute| -%>
5
+ has_one :<%= attribute %>
6
+ <% end -%>
7
+ end
8
+ <% end -%>
@@ -0,0 +1,53 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class AdapterSelectorTest < ActionController::TestCase
6
+ class AdapterSelectorTestController < 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 AdapterSelectorTestController
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
+ id: assigns(:profile).id.to_s,
36
+ type: "profiles",
37
+ attributes: {
38
+ name: "Name 1",
39
+ description: "Description 1",
40
+ }
41
+ }
42
+ }
43
+
44
+ assert_equal expected.to_json, response.body
45
+ end
46
+
47
+ def test_render_skipping_adapter
48
+ get :render_skipping_adapter
49
+ assert_equal '{"attributes":{"name":"Name 1","description":"Description 1","comments":"Comments 1"}}', response.body
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,134 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class ExplicitSerializerTest < ActionController::TestCase
6
+ class ExplicitSerializerTestController < 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
+
59
+ def render_using_explicit_each_serializer
60
+ location = Location.new(id: 42, lat: '-23.550520', lng: '-46.633309')
61
+ place = Place.new(id: 1337, name: 'Amazing Place', locations: [location])
62
+
63
+ render json: place, each_serializer: PlaceSerializer
64
+ end
65
+ end
66
+
67
+ tests ExplicitSerializerTestController
68
+
69
+ def test_render_using_explicit_serializer
70
+ get :render_using_explicit_serializer
71
+
72
+ assert_equal 'application/json', @response.content_type
73
+ assert_equal '{"name":"Name 1"}', @response.body
74
+ end
75
+
76
+ def test_render_array_using_explicit_serializer
77
+ get :render_array_using_explicit_serializer
78
+ assert_equal 'application/json', @response.content_type
79
+
80
+ expected = [
81
+ { 'name' => 'Name 1' },
82
+ { 'name' => 'Name 2' }
83
+ ]
84
+
85
+ assert_equal expected.to_json, @response.body
86
+ end
87
+
88
+ def test_render_array_using_implicit_serializer
89
+ get :render_array_using_implicit_serializer
90
+ assert_equal 'application/json', @response.content_type
91
+
92
+ expected = [
93
+ { 'name' => 'Name 1' },
94
+ { 'name' => 'Name 2' }
95
+ ]
96
+ assert_equal expected.to_json, @response.body
97
+ end
98
+
99
+ def test_render_array_using_explicit_serializer_and_custom_serializers
100
+ get :render_array_using_explicit_serializer_and_custom_serializers
101
+
102
+ expected = [
103
+ { "title" => "New Post",
104
+ "body" => "Body",
105
+ "id" => assigns(:post).id,
106
+ "comments" => [{"id" => 1}, {"id" => 2}],
107
+ "author" => { "id" => assigns(:author).id }
108
+ }
109
+ ]
110
+
111
+ assert_equal expected.to_json, @response.body
112
+ end
113
+
114
+ def test_render_using_explicit_each_serializer
115
+ get :render_using_explicit_each_serializer
116
+
117
+ expected = {
118
+ id: 1337,
119
+ name: "Amazing Place",
120
+ locations: [
121
+ {
122
+ id: 42,
123
+ lat: "-23.550520",
124
+ lng: "-46.633309",
125
+ place: "Nowhere" # is a virtual attribute on LocationSerializer
126
+ }
127
+ ]
128
+ }
129
+
130
+ assert_equal expected.to_json, response.body
131
+ end
132
+ end
133
+ end
134
+ end