active_model_serializers 0.10.1 → 0.10.2

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -4
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +9 -1
  5. data/Rakefile +3 -3
  6. data/active_model_serializers.gemspec +15 -15
  7. data/docs/general/fields.md +31 -0
  8. data/docs/general/rendering.md +7 -2
  9. data/docs/general/serializers.md +32 -0
  10. data/docs/howto/add_pagination_links.md +2 -3
  11. data/docs/integrations/ember-and-json-api.md +25 -10
  12. data/lib/action_controller/serialization.rb +4 -3
  13. data/lib/active_model/serializer.rb +3 -4
  14. data/lib/active_model/serializer/array_serializer.rb +8 -5
  15. data/lib/active_model/serializer/associations.rb +2 -2
  16. data/lib/active_model/serializer/caching.rb +11 -8
  17. data/lib/active_model/serializer/error_serializer.rb +11 -7
  18. data/lib/active_model/serializer/errors_serializer.rb +25 -20
  19. data/lib/active_model/serializer/lint.rb +134 -130
  20. data/lib/active_model/serializer/version.rb +1 -1
  21. data/lib/active_model_serializers/deprecate.rb +1 -1
  22. data/lib/active_model_serializers/model.rb +1 -1
  23. data/lib/active_model_serializers/railtie.rb +1 -1
  24. data/lib/active_model_serializers/register_jsonapi_renderer.rb +37 -35
  25. data/lib/generators/rails/serializer_generator.rb +3 -3
  26. data/lib/grape/active_model_serializers.rb +7 -5
  27. data/test/action_controller/adapter_selector_test.rb +3 -3
  28. data/test/action_controller/json_api/errors_test.rb +5 -6
  29. data/test/action_controller/json_api/linked_test.rb +4 -4
  30. data/test/action_controller/json_api/pagination_test.rb +19 -19
  31. data/test/action_controller/serialization_test.rb +1 -1
  32. data/test/active_model_serializers/json_pointer_test.rb +15 -13
  33. data/test/active_model_serializers/key_transform_test.rb +254 -252
  34. data/test/active_model_serializers/model_test.rb +6 -4
  35. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +2 -2
  36. data/test/adapter/json/transform_test.rb +14 -14
  37. data/test/adapter/json_api/errors_test.rb +9 -9
  38. data/test/adapter/json_api/has_many_test.rb +18 -18
  39. data/test/adapter/json_api/json_api_test.rb +5 -7
  40. data/test/adapter/json_api/linked_test.rb +1 -1
  41. data/test/adapter/json_api/pagination_links_test.rb +6 -6
  42. data/test/adapter/json_api/resource_meta_test.rb +3 -3
  43. data/test/adapter/json_api/transform_test.rb +218 -218
  44. data/test/adapter/json_api/type_test.rb +1 -1
  45. data/test/adapter/json_test.rb +8 -8
  46. data/test/adapter/null_test.rb +1 -2
  47. data/test/adapter/polymorphic_test.rb +5 -5
  48. data/test/adapter_test.rb +1 -1
  49. data/test/benchmark/bm_caching.rb +1 -1
  50. data/test/cache_test.rb +29 -1
  51. data/test/collection_serializer_test.rb +2 -2
  52. data/test/fixtures/poro.rb +2 -2
  53. data/test/grape_test.rb +130 -128
  54. data/test/lint_test.rb +1 -1
  55. data/test/logger_test.rb +13 -11
  56. data/test/serializable_resource_test.rb +12 -16
  57. data/test/serializers/associations_test.rb +10 -10
  58. data/test/serializers/attribute_test.rb +1 -1
  59. data/test/serializers/attributes_test.rb +1 -1
  60. data/test/serializers/fieldset_test.rb +1 -1
  61. data/test/serializers/root_test.rb +1 -1
  62. data/test/serializers/serializer_for_test.rb +3 -1
  63. data/test/support/isolated_unit.rb +4 -2
  64. data/test/support/serialization_testing.rb +7 -5
  65. metadata +3 -3
  66. data/.rubocop_todo.yml +0 -167
@@ -47,7 +47,7 @@ module ActiveModel
47
47
  assert_equal(expected_type, hash.fetch(:data).fetch(:type))
48
48
  end
49
49
 
50
- def with_jsonapi_resource_type inflection
50
+ def with_jsonapi_resource_type(inflection)
51
51
  old_inflection = ActiveModelSerializers.config.jsonapi_resource_type
52
52
  ActiveModelSerializers.config.jsonapi_resource_type = inflection
53
53
  yield
@@ -32,14 +32,14 @@ module ActiveModelSerializers
32
32
  adapter = ActiveModelSerializers::Adapter::Json.new(serializer)
33
33
 
34
34
  assert_equal({
35
- id: 1,
36
- reviews: [
37
- { id: 1, body: 'ZOMG A COMMENT' },
38
- { id: 2, body: 'ZOMG ANOTHER COMMENT' }
39
- ],
40
- writer: { id: 1, name: 'Steve K.' },
41
- site: { id: 1, name: 'My Blog!!' }
42
- }, adapter.serializable_hash[:post])
35
+ id: 1,
36
+ reviews: [
37
+ { id: 1, body: 'ZOMG A COMMENT' },
38
+ { id: 2, body: 'ZOMG ANOTHER COMMENT' }
39
+ ],
40
+ writer: { id: 1, name: 'Steve K.' },
41
+ site: { id: 1, name: 'My Blog!!' }
42
+ }, adapter.serializable_hash[:post])
43
43
  end
44
44
  end
45
45
  end
@@ -4,7 +4,7 @@ module ActiveModelSerializers
4
4
  module Adapter
5
5
  class NullTest < 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
  serializer = ProfileSerializer.new(profile)
9
9
 
10
10
  @adapter = Null.new(serializer)
@@ -20,4 +20,3 @@ module ActiveModelSerializers
20
20
  end
21
21
  end
22
22
  end
23
-
@@ -27,11 +27,11 @@ module ActiveModel
27
27
  id: 1,
28
28
  title: 'headshot-1.jpg',
29
29
  imageable: {
30
- type: 'employee',
31
- employee: {
32
- id: 42,
33
- name: 'Zoop Zoopler'
34
- }
30
+ type: 'employee',
31
+ employee: {
32
+ id: 42,
33
+ name: 'Zoop Zoopler'
34
+ }
35
35
  }
36
36
  }
37
37
 
@@ -51,7 +51,7 @@ module ActiveModelSerializers
51
51
  end
52
52
 
53
53
  def test_create_adapter_with_override
54
- adapter = ActiveModelSerializers::Adapter.create(@serializer, { adapter: :json_api })
54
+ adapter = ActiveModelSerializers::Adapter.create(@serializer, adapter: :json_api)
55
55
  assert_equal ActiveModelSerializers::Adapter::JsonApi, adapter.class
56
56
  end
57
57
 
@@ -86,7 +86,7 @@ class ApiAssertion
86
86
  }
87
87
  ]
88
88
  }
89
- }
89
+ }
90
90
  end
91
91
 
92
92
  def assert_equal(expected, actual, message)
@@ -101,7 +101,7 @@ module ActiveModelSerializers
101
101
  uncached_author_serializer = AuthorSerializer.new(uncached_author)
102
102
 
103
103
  render_object_with_cache(uncached_author)
104
- key = "#{uncached_author_serializer.class._cache_key}/#{uncached_author_serializer.object.id}-#{uncached_author_serializer.object.updated_at.strftime("%Y%m%d%H%M%S%9N")}"
104
+ key = "#{uncached_author_serializer.class._cache_key}/#{uncached_author_serializer.object.id}-#{uncached_author_serializer.object.updated_at.strftime('%Y%m%d%H%M%S%9N')}"
105
105
  key = "#{key}/#{adapter.cache_key}"
106
106
  assert_equal(uncached_author_serializer.attributes.to_json, cache_store.fetch(key).to_json)
107
107
  end
@@ -321,6 +321,34 @@ module ActiveModelSerializers
321
321
  end
322
322
  end
323
323
 
324
+ def test_cache_read_multi_with_fragment_cache_enabled
325
+ post_serializer = Class.new(ActiveModel::Serializer) do
326
+ cache except: [:body]
327
+ end
328
+
329
+ serializers = ActiveModel::Serializer::CollectionSerializer.new([@post, @post], serializer: post_serializer)
330
+
331
+ Timecop.freeze(Time.current) do
332
+ # Warming up.
333
+ options = {}
334
+ adapter_options = {}
335
+ adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
336
+ serializers.serializable_hash(adapter_options, options, adapter_instance)
337
+
338
+ # Should find something with read_multi now
339
+ adapter_options = {}
340
+ serializers.serializable_hash(adapter_options, options, adapter_instance)
341
+ cached_attributes = adapter_options.fetch(:cached_attributes)
342
+
343
+ include_directive = ActiveModelSerializers.default_include_directive
344
+ manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive)
345
+
346
+ refute_equal 0, cached_attributes.size
347
+ refute_equal 0, manual_cached_attributes.size
348
+ assert_equal manual_cached_attributes, cached_attributes
349
+ end
350
+ end
351
+
324
352
  def test_serializer_file_path_on_nix
325
353
  path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
326
354
  caller_line = "#{path}:1:in `<top (required)>'"
@@ -11,7 +11,7 @@ module ActiveModel
11
11
  @comment = Comment.new
12
12
  @post = Post.new
13
13
  @resource = build_named_collection @comment, @post
14
- @serializer = collection_serializer.new(@resource, { some: :options })
14
+ @serializer = collection_serializer.new(@resource, some: :options)
15
15
  end
16
16
 
17
17
  def collection_serializer
@@ -44,7 +44,7 @@ module ActiveModel
44
44
  end
45
45
 
46
46
  def test_serializer_option_not_passed_to_each_serializer
47
- serializers = collection_serializer.new([@post], { serializer: PostSerializer }).to_a
47
+ serializers = collection_serializer.new([@post], serializer: PostSerializer).to_a
48
48
 
49
49
  refute serializers.first.custom_options.key?(:serializer)
50
50
  end
@@ -8,7 +8,7 @@ class Model < ActiveModelSerializers::Model
8
8
  # Convenience when not adding @attributes readers and writers
9
9
  def method_missing(meth, *args)
10
10
  if meth.to_s =~ /^(.*)=$/
11
- attributes[$1.to_sym] = args[0]
11
+ attributes[Regexp.last_match(1).to_sym] = args[0]
12
12
  elsif attributes.key?(meth)
13
13
  attributes[meth]
14
14
  else
@@ -64,7 +64,7 @@ VirtualValue = Class.new(Model)
64
64
  Comment = Class.new(Model) do
65
65
  # Uses a custom non-time-based cache key
66
66
  def cache_key
67
- "#{self.class.name.downcase}/#{self.id}"
67
+ "#{self.class.name.downcase}/#{id}"
68
68
  end
69
69
  end
70
70
 
@@ -5,172 +5,174 @@ require 'kaminari'
5
5
  require 'kaminari/hooks'
6
6
  ::Kaminari::Hooks.init
7
7
 
8
- class ActiveModelSerializers::GrapeTest < ActiveSupport::TestCase
9
- include Rack::Test::Methods
10
- module Models
11
- def self.model1
12
- ARModels::Post.new(id: 1, title: 'Dummy Title', body: 'Lorem Ipsum')
13
- end
8
+ module ActiveModelSerializers
9
+ class GrapeTest < ActiveSupport::TestCase
10
+ include Rack::Test::Methods
11
+ module Models
12
+ def self.model1
13
+ ARModels::Post.new(id: 1, title: 'Dummy Title', body: 'Lorem Ipsum')
14
+ end
14
15
 
15
- def self.model2
16
- ARModels::Post.new(id: 2, title: 'Second Dummy Title', body: 'Second Lorem Ipsum')
17
- end
16
+ def self.model2
17
+ ARModels::Post.new(id: 2, title: 'Second Dummy Title', body: 'Second Lorem Ipsum')
18
+ end
18
19
 
19
- def self.all
20
- @all ||=
21
- begin
22
- model1.save!
23
- model2.save!
24
- ARModels::Post.all
25
- end
26
- end
20
+ def self.all
21
+ @all ||=
22
+ begin
23
+ model1.save!
24
+ model2.save!
25
+ ARModels::Post.all
26
+ end
27
+ end
27
28
 
28
- def self.reset_all
29
- ARModels::Post.delete_all
30
- @all = nil
31
- end
29
+ def self.reset_all
30
+ ARModels::Post.delete_all
31
+ @all = nil
32
+ end
32
33
 
33
- def self.collection_per
34
- 2
35
- end
34
+ def self.collection_per
35
+ 2
36
+ end
36
37
 
37
- def self.collection
38
- @collection ||=
39
- begin
40
- Kaminari.paginate_array(
41
- [
42
- Profile.new(id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
43
- Profile.new(id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2'),
44
- Profile.new(id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3'),
45
- Profile.new(id: 4, name: 'Name 4', description: 'Description 4', comments: 'Comments 4'),
46
- Profile.new(id: 5, name: 'Name 5', description: 'Description 5', comments: 'Comments 5')
38
+ def self.collection
39
+ @collection ||=
40
+ begin
41
+ Kaminari.paginate_array(
42
+ [
43
+ Profile.new(id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
44
+ Profile.new(id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2'),
45
+ Profile.new(id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3'),
46
+ Profile.new(id: 4, name: 'Name 4', description: 'Description 4', comments: 'Comments 4'),
47
+ Profile.new(id: 5, name: 'Name 5', description: 'Description 5', comments: 'Comments 5')
47
48
  ]
48
- ).page(1).per(collection_per)
49
- end
49
+ ).page(1).per(collection_per)
50
+ end
51
+ end
50
52
  end
51
- end
52
53
 
53
- class GrapeTest < Grape::API
54
- format :json
55
- include Grape::ActiveModelSerializers
54
+ class GrapeTest < Grape::API
55
+ format :json
56
+ include Grape::ActiveModelSerializers
56
57
 
57
- resources :grape do
58
- get '/render' do
59
- render Models.model1
60
- end
58
+ resources :grape do
59
+ get '/render' do
60
+ render Models.model1
61
+ end
61
62
 
62
- get '/render_with_json_api' do
63
- post = Models.model1
64
- render post, meta: { page: 1, total_pages: 2 }, adapter: :json_api
65
- end
63
+ get '/render_with_json_api' do
64
+ post = Models.model1
65
+ render post, meta: { page: 1, total_pages: 2 }, adapter: :json_api
66
+ end
66
67
 
67
- get '/render_array_with_json_api' do
68
- posts = Models.all
69
- render posts, adapter: :json_api
70
- end
68
+ get '/render_array_with_json_api' do
69
+ posts = Models.all
70
+ render posts, adapter: :json_api
71
+ end
71
72
 
72
- get '/render_collection_with_json_api' do
73
- posts = Models.collection
74
- render posts, adapter: :json_api
75
- end
73
+ get '/render_collection_with_json_api' do
74
+ posts = Models.collection
75
+ render posts, adapter: :json_api
76
+ end
76
77
 
77
- get '/render_with_implicit_formatter' do
78
- Models.model1
79
- end
78
+ get '/render_with_implicit_formatter' do
79
+ Models.model1
80
+ end
80
81
 
81
- get '/render_array_with_implicit_formatter' do
82
- Models.all
83
- end
82
+ get '/render_array_with_implicit_formatter' do
83
+ Models.all
84
+ end
84
85
 
85
- get '/render_collection_with_implicit_formatter' do
86
- Models.collection
86
+ get '/render_collection_with_implicit_formatter' do
87
+ Models.collection
88
+ end
87
89
  end
88
90
  end
89
- end
90
91
 
91
- def app
92
- Grape::Middleware::Globals.new(GrapeTest.new)
93
- end
92
+ def app
93
+ Grape::Middleware::Globals.new(GrapeTest.new)
94
+ end
94
95
 
95
- def test_formatter_returns_json
96
- get '/grape/render'
96
+ def test_formatter_returns_json
97
+ get '/grape/render'
97
98
 
98
- post = Models.model1
99
- serializable_resource = serializable(post)
99
+ post = Models.model1
100
+ serializable_resource = serializable(post)
100
101
 
101
- assert last_response.ok?
102
- assert_equal serializable_resource.to_json, last_response.body
103
- end
102
+ assert last_response.ok?
103
+ assert_equal serializable_resource.to_json, last_response.body
104
+ end
104
105
 
105
- def test_render_helper_passes_through_options_correctly
106
- get '/grape/render_with_json_api'
106
+ def test_render_helper_passes_through_options_correctly
107
+ get '/grape/render_with_json_api'
107
108
 
108
- post = Models.model1
109
- serializable_resource = serializable(post, serializer: ARModels::PostSerializer, adapter: :json_api, meta: { page: 1, total_pages: 2 })
109
+ post = Models.model1
110
+ serializable_resource = serializable(post, serializer: ARModels::PostSerializer, adapter: :json_api, meta: { page: 1, total_pages: 2 })
110
111
 
111
- assert last_response.ok?
112
- assert_equal serializable_resource.to_json, last_response.body
113
- end
112
+ assert last_response.ok?
113
+ assert_equal serializable_resource.to_json, last_response.body
114
+ end
114
115
 
115
- def test_formatter_handles_arrays
116
- get '/grape/render_array_with_json_api'
116
+ def test_formatter_handles_arrays
117
+ get '/grape/render_array_with_json_api'
117
118
 
118
- posts = Models.all
119
- serializable_resource = serializable(posts, adapter: :json_api)
119
+ posts = Models.all
120
+ serializable_resource = serializable(posts, adapter: :json_api)
120
121
 
121
- assert last_response.ok?
122
- assert_equal serializable_resource.to_json, last_response.body
123
- ensure
124
- Models.reset_all
125
- end
122
+ assert last_response.ok?
123
+ assert_equal serializable_resource.to_json, last_response.body
124
+ ensure
125
+ Models.reset_all
126
+ end
126
127
 
127
- def test_formatter_handles_collections
128
- get '/grape/render_collection_with_json_api'
129
- assert last_response.ok?
128
+ def test_formatter_handles_collections
129
+ get '/grape/render_collection_with_json_api'
130
+ assert last_response.ok?
130
131
 
131
- representation = JSON.parse(last_response.body)
132
- assert representation.include?('data')
133
- assert representation['data'].count == Models.collection_per
134
- assert representation.include?('links')
135
- assert representation['links'].count > 0
136
- end
132
+ representation = JSON.parse(last_response.body)
133
+ assert representation.include?('data')
134
+ assert representation['data'].count == Models.collection_per
135
+ assert representation.include?('links')
136
+ assert representation['links'].count > 0
137
+ end
138
+
139
+ def test_implicit_formatter
140
+ post = Models.model1
141
+ serializable_resource = serializable(post, adapter: :json_api)
137
142
 
138
- def test_implicit_formatter
139
- post = Models.model1
140
- serializable_resource = serializable(post, adapter: :json_api)
143
+ with_adapter :json_api do
144
+ get '/grape/render_with_implicit_formatter'
145
+ end
141
146
 
142
- with_adapter :json_api do
143
- get '/grape/render_with_implicit_formatter'
147
+ assert last_response.ok?
148
+ assert_equal serializable_resource.to_json, last_response.body
144
149
  end
145
150
 
146
- assert last_response.ok?
147
- assert_equal serializable_resource.to_json, last_response.body
148
- end
151
+ def test_implicit_formatter_handles_arrays
152
+ posts = Models.all
153
+ serializable_resource = serializable(posts, adapter: :json_api)
149
154
 
150
- def test_implicit_formatter_handles_arrays
151
- posts = Models.all
152
- serializable_resource = serializable(posts, adapter: :json_api)
155
+ with_adapter :json_api do
156
+ get '/grape/render_array_with_implicit_formatter'
157
+ end
153
158
 
154
- with_adapter :json_api do
155
- get '/grape/render_array_with_implicit_formatter'
159
+ assert last_response.ok?
160
+ assert_equal serializable_resource.to_json, last_response.body
161
+ ensure
162
+ Models.reset_all
156
163
  end
157
164
 
158
- assert last_response.ok?
159
- assert_equal serializable_resource.to_json, last_response.body
160
- ensure
161
- Models.reset_all
162
- end
165
+ def test_implicit_formatter_handles_collections
166
+ with_adapter :json_api do
167
+ get '/grape/render_collection_with_implicit_formatter'
168
+ end
163
169
 
164
- def test_implicit_formatter_handles_collections
165
- with_adapter :json_api do
166
- get '/grape/render_collection_with_implicit_formatter'
170
+ representation = JSON.parse(last_response.body)
171
+ assert last_response.ok?
172
+ assert representation.include?('data')
173
+ assert representation['data'].count == Models.collection_per
174
+ assert representation.include?('links')
175
+ assert representation['links'].count > 0
167
176
  end
168
-
169
- representation = JSON.parse(last_response.body)
170
- assert last_response.ok?
171
- assert representation.include?('data')
172
- assert representation['data'].count == Models.collection_per
173
- assert representation.include?('links')
174
- assert representation['links'].count > 0
175
177
  end
176
178
  end