active_model_serializers 0.10.7 → 0.10.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c3a5900ed1c671e57b90ea00e3130ad3a5fe4939a6a1c36e1481dbdeeef3199
4
- data.tar.gz: 59ed63aa89861c650f87ba5bfeb5dfc90c997cd8fe4542129f28d1194d3c24ff
3
+ metadata.gz: 7232014fa13e7bf11951db024282a8518806ccdd81aead05ce694398e8f16439
4
+ data.tar.gz: 8337471a240ac4e1931fd71fbfbbf096e8bb5989ce51bce920d2f266aa0ac775
5
5
  SHA512:
6
- metadata.gz: 0ee2569a69953e286d63861bb01a37836ee9b25463980da1dc561815e0d7e7902aa1b1d344b265bb50f3c41b1e93ea6cfec2ba241c5314511d4a55a5082f5ce0
7
- data.tar.gz: d011e2d950d8b7869d4f49139d23cf994f2b1f6e8319aa2a3ff018d4f1c578d24bb64cfe632c912e91edd92e0f5945fa58a1a7742b611ef33c5a4d0a14dfbc70
6
+ metadata.gz: 33a114c6a2f87df622d820e8d04b9ce3099891a83f30527d93c159f0014a4fc3a60f883884b6d3a16fa4daf9f65cce1a57410eee4111391351c4199a73e8ca1c
7
+ data.tar.gz: 5ac71dcb57c2fd16b328cc849b948c6ae0d8cc6d409a1f0b3c942033c439e37c8c8fd8df3be5d80a8a153cb86e38d5cfe93a40fc553f09db739514759ca935a2
@@ -40,6 +40,8 @@ matrix:
40
40
  # - { rvm: jruby-head, jdk: oraclejdk8, env: "RAILS_VERSION=5.1 JRUBY_OPTS='--dev -J-Xmx1024M --debug'" }
41
41
  exclude:
42
42
  - { rvm: 2.1.10, env: RAILS_VERSION=master }
43
+ - { rvm: 2.2.8, env: RAILS_VERSION=master }
44
+ - { rvm: 2.3.5, env: RAILS_VERSION=master }
43
45
  - { rvm: 2.1.10, env: RAILS_VERSION=5.0 }
44
46
  - { rvm: 2.1.10, env: RAILS_VERSION=5.1 }
45
47
  - { rvm: 2.4.2, env: RAILS_VERSION=4.1 }
@@ -1,6 +1,6 @@
1
1
  ## 0.10.x
2
2
 
3
- ### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.7...0-10-stable)
3
+ ### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.8...0-10-stable)
4
4
 
5
5
  Breaking changes:
6
6
 
@@ -8,8 +8,23 @@ Features:
8
8
 
9
9
  Fixes:
10
10
 
11
+
11
12
  Misc:
12
13
 
14
+ ### [v0.10.8 (2018-11-01)](https://github.com/rails-api/active_model_serializers/compare/v0.10.7...v0.10.8)
15
+
16
+ Features:
17
+ - [#2279](https://github.com/rails-api/active_model_serializers/pull/2279) Support condition options in serializer link statements
18
+
19
+ Fixes:
20
+
21
+ - [#2296](https://github.com/rails-api/active_model_serializers/pull/2296) Fixes #2295 (@Hirurg103)
22
+ - Fix finding of namespaced serializer and non-namespaced model.
23
+ - [#2289](https://github.com/rails-api/active_model_serializers/pull/2289) Fixes #2255 (@f-mer)
24
+ - Fix autoloading race condition, especially in Rails 5.
25
+ - [#2299](https://github.com/rails-api/active_model_serializers/pull/2299) Fixes #2270 (@chau-bao-long via #2276)
26
+ - Fix reflection thread-safety bug
27
+
13
28
  ### [v0.10.7 (2017-11-14)](https://github.com/rails-api/active_model_serializers/compare/v0.10.6...v0.10.7)
14
29
 
15
30
  Regressions Fixed From v0.10.6:
data/Gemfile CHANGED
@@ -54,9 +54,9 @@ group :test do
54
54
  gem 'sqlite3', platform: (@windows_platforms + [:ruby])
55
55
  platforms :jruby do
56
56
  if version == 'master' || version >= '5'
57
- gem 'activerecord-jdbcsqlite3-adapter', '>= 1.3.0' # github: 'jruby/activerecord-jdbc-adapter', branch: 'master'
57
+ gem 'activerecord-jdbcsqlite3-adapter', '~> 50'
58
58
  else
59
- gem 'activerecord-jdbcsqlite3-adapter'
59
+ gem 'activerecord-jdbcsqlite3-adapter', '~> 1.3.0'
60
60
  end
61
61
  end
62
62
  gem 'codeclimate-test-reporter', require: false
data/README.md CHANGED
@@ -266,8 +266,8 @@ to know about, but not part of ActiveModelSerializers.)
266
266
 
267
267
  - An `ActiveRecord::Base` object.
268
268
  - Any Ruby object that passes the
269
- [Lint](http://www.rubydoc.info/github/rails-api/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
270
- [code](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer/lint.rb).
269
+ [Lint](https://www.rubydoc.info/gems/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
270
+ [(code)](lib/active_model/serializer/lint.rb).
271
271
 
272
272
  ActiveModelSerializers provides a
273
273
  [`ActiveModelSerializers::Model`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/model.rb),
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
39
39
  # 'activesupport', rails_versions
40
40
  # 'i18n,
41
41
  # 'tzinfo'
42
- # 'minitest'
42
+ spec.add_development_dependency 'minitest', ['~> 5.0', '< 5.11']
43
43
  # 'thread_safe'
44
44
 
45
45
  spec.add_runtime_dependency 'jsonapi-renderer', ['>= 0.1.1.beta1', '< 0.3']
@@ -65,7 +65,7 @@ Where:
65
65
  - `virtual_value:`
66
66
  - `polymorphic:` defines if polymorphic relation type should be nested in serialized association.
67
67
  - `type:` the resource type as used by JSON:API, especially on a `belongs_to` relationship.
68
- - `class_name:` used to determine `type` when `type` not given
68
+ - `class_name:` the (String) model name used to determine `type`, when `type` is not given. e.g. `class_name: "Comment"` would imply the type `comments`
69
69
  - `foreign_key:` used by JSON:API on a `belongs_to` relationship to avoid unnecessarily loading the association object.
70
70
  - `namespace:` used when looking up the serializer and `serializer` is not given. Falls back to the parent serializer's `:namespace` instance options, which, when present, comes from the render options. See [Rendering#namespace](rendering.md#namespace] for more details.
71
71
  - optional: `&block` is a context that returns the association's attributes.
@@ -81,6 +81,7 @@ e.g.
81
81
  ```ruby
82
82
  has_one :bio
83
83
  has_one :blog, key: :site
84
+ has_one :blog, class_name: "Blog"
84
85
  has_one :maker, virtual_value: { id: 1 }
85
86
 
86
87
  has_one :blog do |serializer|
@@ -114,6 +115,7 @@ e.g.
114
115
  has_many :comments
115
116
  has_many :comments, key: :reviews
116
117
  has_many :comments, serializer: CommentPreviewSerializer
118
+ has_many :comments, class_name: "Comment"
117
119
  has_many :reviews, virtual_value: [{ id: 1 }, { id: 2 }]
118
120
  has_many :comments, key: :last_comments do
119
121
  last(1)
@@ -127,6 +129,7 @@ e.g.
127
129
  ```ruby
128
130
  belongs_to :author, serializer: AuthorPreviewSerializer
129
131
  belongs_to :author, key: :writer
132
+ belongs_to :author, class_name: "Author"
130
133
  belongs_to :post
131
134
  belongs_to :blog
132
135
  def blog
@@ -235,6 +238,15 @@ link :other, 'https://example.com/resource'
235
238
  link(:posts) { link_author_posts_url(object) }
236
239
  ```
237
240
 
241
+ Just like attributes, links also support conditions in options
242
+ ```ruby
243
+ link(:secret, if: :internal?) { object.secret_link }
244
+
245
+ def internal?
246
+ instance_options[:context] == :internal
247
+ end
248
+ ```
249
+
238
250
  #### #object
239
251
 
240
252
  The object being serialized.
@@ -294,7 +306,7 @@ end
294
306
  Whether you write the method as above or as `object.comments.where(created_by: scope)`
295
307
  is a matter of preference (assuming `scope_name` has been set).
296
308
 
297
- Keep in mind that the scope can be set to any available controller reference. This can be utilized to provide access to any other data scopes or presentation helpers.
309
+ Keep in mind that the scope can be set to any available controller reference. This can be utilized to provide access to any other data scopes or presentation helpers.
298
310
 
299
311
  ##### Controller Authorization Context
300
312
 
@@ -381,7 +393,7 @@ class PostsController < ActionController::Base
381
393
  end
382
394
  end
383
395
  ```
384
- Note that any controller reference which provides the desired scope is acceptable, such as another controller method for loading a different resource or reference to helpers. For example, `ActionController::API` does not include `ActionView::ViewContext`, and would need a different reference for passing any helpers into a serializer via `serialization_scope`.
396
+ Note that any controller reference which provides the desired scope is acceptable, such as another controller method for loading a different resource or reference to helpers. For example, `ActionController::API` does not include `ActionView::ViewContext`, and would need a different reference for passing any helpers into a serializer via `serialization_scope`.
385
397
 
386
398
  #### #read_attribute_for_serialization(key)
387
399
 
@@ -474,7 +486,7 @@ the `ActiveModel::Serializer.serializer_for` method to return a serializer class
474
486
  ```ruby
475
487
  class MySerializer < ActiveModel::Serializer
476
488
  def self.serializer_for(model, options)
477
- return SparseAdminSerializer if model.class == 'Admin'
489
+ return SparseAdminSerializer if model.class.name == 'Admin'
478
490
  super
479
491
  end
480
492
 
@@ -18,16 +18,17 @@ module ActiveModel
18
18
  # @see #serializable_hash for more details on these valid keys.
19
19
  SERIALIZABLE_HASH_VALID_KEYS = [:only, :except, :methods, :include, :root].freeze
20
20
  extend ActiveSupport::Autoload
21
- autoload :Adapter
22
- autoload :Null
23
- autoload :Attribute
24
- autoload :Association
25
- autoload :Reflection
26
- autoload :SingularReflection
27
- autoload :CollectionReflection
28
- autoload :BelongsToReflection
29
- autoload :HasOneReflection
30
- autoload :HasManyReflection
21
+ eager_autoload do
22
+ autoload :Adapter
23
+ autoload :Null
24
+ autoload :Attribute
25
+ autoload :Link
26
+ autoload :Association
27
+ autoload :Reflection
28
+ autoload :BelongsToReflection
29
+ autoload :HasOneReflection
30
+ autoload :HasManyReflection
31
+ end
31
32
  include ActiveSupport::Configurable
32
33
  include Caching
33
34
 
@@ -275,9 +276,14 @@ module ActiveModel
275
276
  # link(:self) { "http://example.com/resource/#{object.id}" }
276
277
  # @example
277
278
  # link :resource, "http://example.com/resource"
279
+ # @example
280
+ # link(:callback, if: :internal?), { "http://example.com/callback" }
278
281
  #
279
- def self.link(name, value = nil, &block)
280
- _links[name] = block || value
282
+ def self.link(name, *args, &block)
283
+ options = args.extract_options!
284
+ # For compatibility with the use case of passing link directly as string argument
285
+ # without block, we are creating a wrapping block
286
+ _links[name] = Link.new(name, options, block || ->(_serializer) { args.first })
281
287
  end
282
288
 
283
289
  # Set the JSON API meta attribute of a serializer.
@@ -341,7 +347,7 @@ module ActiveModel
341
347
  return Enumerator.new {} unless object
342
348
 
343
349
  Enumerator.new do |y|
344
- self.class._reflections.each do |key, reflection|
350
+ (self.instance_reflections ||= self.class._reflections.deep_dup).each do |key, reflection|
345
351
  next if reflection.excluded?(self)
346
352
  next unless include_directive.key?(key)
347
353
 
@@ -405,6 +411,6 @@ module ActiveModel
405
411
 
406
412
  protected
407
413
 
408
- attr_accessor :instance_options
414
+ attr_accessor :instance_options, :instance_reflections
409
415
  end
410
416
  end
@@ -19,11 +19,10 @@ module ActiveModel
19
19
 
20
20
  # @api private
21
21
  def serializable_hash(adapter_options, options, adapter_instance)
22
- include_directive = ActiveModel::Serializer.include_directive_from_options(adapter_options)
23
- adapter_options[:cached_attributes] ||= ActiveModel::Serializer.cache_read_multi(self, adapter_instance, include_directive)
24
- adapter_opts = adapter_options.merge(include_directive: include_directive)
22
+ options[:include_directive] ||= ActiveModel::Serializer.include_directive_from_options(adapter_options)
23
+ options[:cached_attributes] ||= ActiveModel::Serializer.cache_read_multi(self, adapter_instance, options[:include_directive])
25
24
  serializers.map do |serializer|
26
- serializer.serializable_hash(adapter_opts, options, adapter_instance)
25
+ serializer.serializable_hash(adapter_options, options, adapter_instance)
27
26
  end
28
27
  end
29
28
 
@@ -48,8 +47,7 @@ module ActiveModel
48
47
  # 4. key may be nil for empty collection and no serializer option
49
48
  key &&= key.pluralize
50
49
  # 5. fail if the key cannot be determined
51
- key || fail(ArgumentError, 'Cannot infer root key from collection type. Please
52
- specify the root or each_serializer option, or render a JSON String')
50
+ key || fail(ArgumentError, 'Cannot infer root key from collection type. Please specify the root or each_serializer option, or render a JSON String')
53
51
  end
54
52
  # rubocop:enable Metrics/CyclomaticComplexity
55
53
 
@@ -76,6 +76,7 @@ module ActiveModel
76
76
  serializer_options[:serializer_context_class] = association_options.fetch(:parent_serializer).class
77
77
  serializer = reflection_options.fetch(:serializer, nil)
78
78
  serializer_options[:serializer] = serializer if serializer
79
+ serializer_options[:namespace] = reflection_options[:namespace] if reflection_options[:namespace]
79
80
  serializer_class.new(object, serializer_options)
80
81
  end
81
82
 
@@ -0,0 +1,21 @@
1
+ require 'active_model/serializer/field'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ # Holds all the data about a serializer link
6
+ #
7
+ # @example
8
+ # class PostSerializer < ActiveModel::Serializer
9
+ # link :callback, if: :internal? do
10
+ # object.callback_link
11
+ # end
12
+ #
13
+ # def internal?
14
+ # instance_options[:internal] == true
15
+ # end
16
+ # end
17
+ #
18
+ class Link < Field
19
+ end
20
+ end
21
+ end
@@ -151,6 +151,9 @@ module ActiveModel
151
151
  # @yield [ActiveModel::Serializer]
152
152
  # @return [:nil, associated resource or resource collection]
153
153
  def value(serializer, include_slice)
154
+ # NOTE(BF): This method isn't thread-safe because the _reflections class attribute is not thread-safe
155
+ # Therefore, when we build associations from reflections, we dup the entire reflection instance.
156
+ # Better solutions much appreciated!
154
157
  @object = serializer.object
155
158
  @scope = serializer.scope
156
159
 
@@ -1,5 +1,5 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
- VERSION = '0.10.7'.freeze
3
+ VERSION = '0.10.8'.freeze
4
4
  end
5
5
  end
@@ -5,16 +5,19 @@ require 'active_support/core_ext/string/inflections'
5
5
  require 'active_support/json'
6
6
  module ActiveModelSerializers
7
7
  extend ActiveSupport::Autoload
8
- autoload :Model
9
- autoload :Callbacks
10
- autoload :Deserialization
11
- autoload :SerializableResource
12
- autoload :Logging
13
- autoload :Test
14
- autoload :Adapter
15
- autoload :JsonPointer
16
- autoload :Deprecate
17
- autoload :LookupChain
8
+ eager_autoload do
9
+ autoload :Model
10
+ autoload :Callbacks
11
+ autoload :SerializableResource
12
+ autoload :SerializationContext
13
+ autoload :Logging
14
+ autoload :Test
15
+ autoload :Adapter
16
+ autoload :JsonPointer
17
+ autoload :Deprecate
18
+ autoload :LookupChain
19
+ autoload :Deserialization
20
+ end
18
21
 
19
22
  class << self; attr_accessor :logger; end
20
23
  self.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
@@ -46,6 +49,11 @@ module ActiveModelSerializers
46
49
  $VERBOSE = original_verbose
47
50
  end
48
51
 
52
+ def self.eager_load!
53
+ super
54
+ ActiveModel::Serializer.eager_load!
55
+ end
56
+
49
57
  require 'active_model/serializer/version'
50
58
  require 'active_model/serializer'
51
59
  require 'active_model/serializable_resource'
@@ -22,14 +22,16 @@ module ActiveModelSerializers
22
22
  module Adapter
23
23
  class JsonApi < Base
24
24
  extend ActiveSupport::Autoload
25
- autoload :Jsonapi
26
- autoload :ResourceIdentifier
27
- autoload :Relationship
28
- autoload :Link
29
- autoload :PaginationLinks
30
- autoload :Meta
31
- autoload :Error
32
- autoload :Deserialization
25
+ eager_autoload do
26
+ autoload :Jsonapi
27
+ autoload :ResourceIdentifier
28
+ autoload :Link
29
+ autoload :PaginationLinks
30
+ autoload :Meta
31
+ autoload :Error
32
+ autoload :Deserialization
33
+ autoload :Relationship
34
+ end
33
35
 
34
36
  def self.default_key_transform
35
37
  :dash
@@ -480,7 +482,8 @@ module ActiveModelSerializers
480
482
  # }.reject! {|_,v| v.nil? }
481
483
  def links_for(serializer)
482
484
  serializer._links.each_with_object({}) do |(name, value), hash|
483
- result = Link.new(serializer, value).as_json
485
+ next if value.excluded?(serializer)
486
+ result = Link.new(serializer, value.block).as_json
484
487
  hash[name] = result if result
485
488
  end
486
489
  end
@@ -5,6 +5,8 @@ require 'action_controller/serialization'
5
5
 
6
6
  module ActiveModelSerializers
7
7
  class Railtie < Rails::Railtie
8
+ config.eager_load_namespaces << ActiveModelSerializers
9
+
8
10
  config.to_prepare do
9
11
  ActiveModel::Serializer.serializers_cache.clear
10
12
  end
@@ -457,13 +457,19 @@ module ActionController
457
457
  end
458
458
 
459
459
  def test_render_event_is_emitted
460
- subscriber = ::ActiveSupport::Notifications.subscribe('render.active_model_serializers') do |name|
461
- @name = name
460
+ subscriber = ::ActiveSupport::Notifications.subscribe('render.active_model_serializers') do |subscribed_event|
461
+ @subscribed_event = subscribed_event
462
462
  end
463
463
 
464
464
  get :render_using_implicit_serializer
465
465
 
466
- assert_equal 'render.active_model_serializers', @name
466
+ subscribed_event_name =
467
+ if @subscribed_event.is_a?(String)
468
+ @subscribed_event
469
+ else
470
+ @subscribed_event.name # is a ActiveSupport::Notifications::Event
471
+ end
472
+ assert_equal 'render.active_model_serializers', subscribed_event_name
467
473
  ensure
468
474
  ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
469
475
  end
@@ -17,7 +17,21 @@ module ActiveModelSerializers
17
17
  link :yet_another do
18
18
  "http://example.com/resource/#{object.id}"
19
19
  end
20
+ link :conditional1, if: -> { instance_truth } do
21
+ "http://example.com/conditional1/#{object.id}"
22
+ end
23
+ link :conditional2, if: :instance_falsey do
24
+ "http://example.com/conditional2/#{object.id}"
25
+ end
20
26
  link(:nil) { nil }
27
+
28
+ def instance_truth
29
+ true
30
+ end
31
+
32
+ def instance_falsey
33
+ false
34
+ end
21
35
  end
22
36
 
23
37
  def setup
@@ -85,7 +99,8 @@ module ActiveModelSerializers
85
99
  :"link-authors" => 'http://example.com/link_authors',
86
100
  resource: 'http://example.com/resource',
87
101
  posts: 'http://example.com/link_authors/1337/posts',
88
- :"yet-another" => 'http://example.com/resource/1337'
102
+ :"yet-another" => 'http://example.com/resource/1337',
103
+ conditional1: 'http://example.com/conditional1/1337'
89
104
  }
90
105
  assert_equal(expected, hash[:data][:links])
91
106
  end
@@ -415,7 +415,7 @@ module ActiveModelSerializers
415
415
  adapter_options = {}
416
416
  adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
417
417
  serializers.serializable_hash(adapter_options, options, adapter_instance)
418
- cached_attributes = adapter_options.fetch(:cached_attributes).with_indifferent_access
418
+ cached_attributes = options.fetch(:cached_attributes).with_indifferent_access
419
419
 
420
420
  include_directive = ActiveModelSerializers.default_include_directive
421
421
  manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive).with_indifferent_access
@@ -446,9 +446,9 @@ module ActiveModelSerializers
446
446
  serializers.serializable_hash(adapter_options, options, adapter_instance)
447
447
 
448
448
  # Should find something with read_multi now
449
- adapter_options = {}
449
+ options = {}
450
450
  serializers.serializable_hash(adapter_options, options, adapter_instance)
451
- cached_attributes = adapter_options.fetch(:cached_attributes)
451
+ cached_attributes = options.fetch(:cached_attributes)
452
452
 
453
453
  include_directive = ActiveModelSerializers.default_include_directive
454
454
  manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive)
@@ -285,6 +285,56 @@ module ActiveModel
285
285
  end
286
286
  end
287
287
 
288
+ class AssociationsNamespacedSerializersTest < ActiveSupport::TestCase
289
+ class Post < ::Model
290
+ associations :comments, :author, :description
291
+
292
+ def latest_comments
293
+ comments[0..3]
294
+ end
295
+ end
296
+ class Comment < ::Model; end
297
+ class Author < ::Model; end
298
+ class Description < ::Model; end
299
+
300
+ class ResourceNamespace
301
+ class PostSerializer < ActiveModel::Serializer
302
+ has_many :comments, namespace: ResourceNamespace
303
+ has_many :latest_comments, namespace: ResourceNamespace
304
+ belongs_to :author, namespace: ResourceNamespace
305
+ has_one :description, namespace: ResourceNamespace
306
+ end
307
+ class CommentSerializer < ActiveModel::Serializer; end
308
+ class AuthorSerializer < ActiveModel::Serializer; end
309
+ class DescriptionSerializer < ActiveModel::Serializer; end
310
+ end
311
+
312
+ def setup
313
+ @comment = Comment.new
314
+ @author = Author.new
315
+ @description = Description.new
316
+ @post = Post.new(comments: [@comment],
317
+ author: @author,
318
+ description: @description)
319
+ @post_serializer = ResourceNamespace::PostSerializer.new(@post)
320
+ end
321
+
322
+ def test_associations_namespaced_serializers
323
+ @post_serializer.associations.each do |association|
324
+ case association.key
325
+ when :comments, :latest_comments
326
+ assert_instance_of(ResourceNamespace::CommentSerializer, association.lazy_association.serializer.first)
327
+ when :author
328
+ assert_instance_of(ResourceNamespace::AuthorSerializer, association.lazy_association.serializer)
329
+ when :description
330
+ assert_instance_of(ResourceNamespace::DescriptionSerializer, association.lazy_association.serializer)
331
+ else
332
+ flunk "Unknown association: #{key}"
333
+ end
334
+ end
335
+ end
336
+ end
337
+
288
338
  class NestedSerializersTest < ActiveSupport::TestCase
289
339
  class Post < ::Model
290
340
  associations :comments, :author, :description
@@ -423,5 +423,57 @@ module ActiveModel
423
423
  end
424
424
  # rubocop:enable Metrics/AbcSize
425
425
  end
426
+ class ThreadedReflectionTest < ActiveSupport::TestCase
427
+ class Post < ::Model
428
+ attributes :id, :title, :body
429
+ associations :comments
430
+ end
431
+ class Comment < ::Model
432
+ attributes :id, :body
433
+ associations :post
434
+ end
435
+ class CommentSerializer < ActiveModel::Serializer
436
+ type 'comment'
437
+ attributes :id, :body
438
+ has_one :post
439
+ end
440
+ class PostSerializer < ActiveModel::Serializer
441
+ type 'post'
442
+ attributes :id, :title, :body
443
+ has_many :comments, serializer: CommentSerializer do
444
+ sleep 0.1
445
+ object.comments
446
+ end
447
+ end
448
+
449
+ # per https://github.com/rails-api/active_model_serializers/issues/2270
450
+ def test_concurrent_serialization
451
+ post1 = Post.new(id: 1, title: 'Post 1 Title', body: 'Post 1 Body')
452
+ post1.comments = [Comment.new(id: 1, body: 'Comment on Post 1', post: post1)]
453
+ post2 = Post.new(id: 2, title: 'Post 2 Title', body: 'Post 2 Body')
454
+ post2.comments = [Comment.new(id: 2, body: 'Comment on Post 2', post: post2)]
455
+ serialized_posts = {
456
+ first: Set.new,
457
+ second: Set.new
458
+ }
459
+ t1 = Thread.new do
460
+ 10.times do
461
+ serialized_posts[:first] << PostSerializer.new(post1, {}).to_json
462
+ end
463
+ end
464
+ t2 = Thread.new do
465
+ 10.times do
466
+ serialized_posts[:second] << PostSerializer.new(post2, {}).to_json
467
+ end
468
+ end
469
+ t1.join
470
+ t2.join
471
+ expected_first_post_serialization = '{"id":1,"title":"Post 1 Title","body":"Post 1 Body","comments":[{"id":1,"body":"Comment on Post 1"}]}'
472
+ expected_second_post_serialization = '{"id":2,"title":"Post 2 Title","body":"Post 2 Body","comments":[{"id":2,"body":"Comment on Post 2"}]}'
473
+
474
+ assert_equal [expected_second_post_serialization], serialized_posts[:second].to_a
475
+ assert_equal [expected_first_post_serialization], serialized_posts[:first].to_a
476
+ end
477
+ end
426
478
  end
427
479
  end
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_model_serializers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.7
4
+ version: 0.10.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Klabnik
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-15 00:00:00.000000000 Z
11
+ date: 2018-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
+ name: activemodel
14
15
  requirement: !ruby/object:Gem::Requirement
15
16
  requirements:
16
17
  - - ">="
@@ -19,9 +20,8 @@ dependencies:
19
20
  - - "<"
20
21
  - !ruby/object:Gem::Version
21
22
  version: '6'
22
- name: activemodel
23
- prerelease: false
24
23
  type: :runtime
24
+ prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
@@ -31,6 +31,7 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: '6'
33
33
  - !ruby/object:Gem::Dependency
34
+ name: actionpack
34
35
  requirement: !ruby/object:Gem::Requirement
35
36
  requirements:
36
37
  - - ">="
@@ -39,9 +40,8 @@ dependencies:
39
40
  - - "<"
40
41
  - !ruby/object:Gem::Version
41
42
  version: '6'
42
- name: actionpack
43
- prerelease: false
44
43
  type: :runtime
44
+ prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
46
46
  requirements:
47
47
  - - ">="
@@ -51,6 +51,7 @@ dependencies:
51
51
  - !ruby/object:Gem::Version
52
52
  version: '6'
53
53
  - !ruby/object:Gem::Dependency
54
+ name: railties
54
55
  requirement: !ruby/object:Gem::Requirement
55
56
  requirements:
56
57
  - - ">="
@@ -59,9 +60,8 @@ dependencies:
59
60
  - - "<"
60
61
  - !ruby/object:Gem::Version
61
62
  version: '6'
62
- name: railties
63
- prerelease: false
64
63
  type: :development
64
+ prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
@@ -71,6 +71,27 @@ dependencies:
71
71
  - !ruby/object:Gem::Version
72
72
  version: '6'
73
73
  - !ruby/object:Gem::Dependency
74
+ name: minitest
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '5.0'
80
+ - - "<"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.11'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.0'
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '5.11'
93
+ - !ruby/object:Gem::Dependency
94
+ name: jsonapi-renderer
74
95
  requirement: !ruby/object:Gem::Requirement
75
96
  requirements:
76
97
  - - ">="
@@ -79,9 +100,8 @@ dependencies:
79
100
  - - "<"
80
101
  - !ruby/object:Gem::Version
81
102
  version: '0.3'
82
- name: jsonapi-renderer
83
- prerelease: false
84
103
  type: :runtime
104
+ prerelease: false
85
105
  version_requirements: !ruby/object:Gem::Requirement
86
106
  requirements:
87
107
  - - ">="
@@ -91,20 +111,21 @@ dependencies:
91
111
  - !ruby/object:Gem::Version
92
112
  version: '0.3'
93
113
  - !ruby/object:Gem::Dependency
114
+ name: case_transform
94
115
  requirement: !ruby/object:Gem::Requirement
95
116
  requirements:
96
117
  - - ">="
97
118
  - !ruby/object:Gem::Version
98
119
  version: '0.2'
99
- name: case_transform
100
- prerelease: false
101
120
  type: :runtime
121
+ prerelease: false
102
122
  version_requirements: !ruby/object:Gem::Requirement
103
123
  requirements:
104
124
  - - ">="
105
125
  - !ruby/object:Gem::Version
106
126
  version: '0.2'
107
127
  - !ruby/object:Gem::Dependency
128
+ name: activerecord
108
129
  requirement: !ruby/object:Gem::Requirement
109
130
  requirements:
110
131
  - - ">="
@@ -113,9 +134,8 @@ dependencies:
113
134
  - - "<"
114
135
  - !ruby/object:Gem::Version
115
136
  version: '6'
116
- name: activerecord
117
- prerelease: false
118
137
  type: :development
138
+ prerelease: false
119
139
  version_requirements: !ruby/object:Gem::Requirement
120
140
  requirements:
121
141
  - - ">="
@@ -125,20 +145,21 @@ dependencies:
125
145
  - !ruby/object:Gem::Version
126
146
  version: '6'
127
147
  - !ruby/object:Gem::Dependency
148
+ name: kaminari
128
149
  requirement: !ruby/object:Gem::Requirement
129
150
  requirements:
130
151
  - - "~>"
131
152
  - !ruby/object:Gem::Version
132
153
  version: 0.16.3
133
- name: kaminari
134
- prerelease: false
135
154
  type: :development
155
+ prerelease: false
136
156
  version_requirements: !ruby/object:Gem::Requirement
137
157
  requirements:
138
158
  - - "~>"
139
159
  - !ruby/object:Gem::Version
140
160
  version: 0.16.3
141
161
  - !ruby/object:Gem::Dependency
162
+ name: will_paginate
142
163
  requirement: !ruby/object:Gem::Requirement
143
164
  requirements:
144
165
  - - "~>"
@@ -147,9 +168,8 @@ dependencies:
147
168
  - - ">="
148
169
  - !ruby/object:Gem::Version
149
170
  version: 3.0.7
150
- name: will_paginate
151
- prerelease: false
152
171
  type: :development
172
+ prerelease: false
153
173
  version_requirements: !ruby/object:Gem::Requirement
154
174
  requirements:
155
175
  - - "~>"
@@ -159,48 +179,49 @@ dependencies:
159
179
  - !ruby/object:Gem::Version
160
180
  version: 3.0.7
161
181
  - !ruby/object:Gem::Dependency
182
+ name: bundler
162
183
  requirement: !ruby/object:Gem::Requirement
163
184
  requirements:
164
185
  - - "~>"
165
186
  - !ruby/object:Gem::Version
166
187
  version: '1.6'
167
- name: bundler
168
- prerelease: false
169
188
  type: :development
189
+ prerelease: false
170
190
  version_requirements: !ruby/object:Gem::Requirement
171
191
  requirements:
172
192
  - - "~>"
173
193
  - !ruby/object:Gem::Version
174
194
  version: '1.6'
175
195
  - !ruby/object:Gem::Dependency
196
+ name: simplecov
176
197
  requirement: !ruby/object:Gem::Requirement
177
198
  requirements:
178
199
  - - "~>"
179
200
  - !ruby/object:Gem::Version
180
201
  version: '0.11'
181
- name: simplecov
182
- prerelease: false
183
202
  type: :development
203
+ prerelease: false
184
204
  version_requirements: !ruby/object:Gem::Requirement
185
205
  requirements:
186
206
  - - "~>"
187
207
  - !ruby/object:Gem::Version
188
208
  version: '0.11'
189
209
  - !ruby/object:Gem::Dependency
210
+ name: timecop
190
211
  requirement: !ruby/object:Gem::Requirement
191
212
  requirements:
192
213
  - - "~>"
193
214
  - !ruby/object:Gem::Version
194
215
  version: '0.7'
195
- name: timecop
196
- prerelease: false
197
216
  type: :development
217
+ prerelease: false
198
218
  version_requirements: !ruby/object:Gem::Requirement
199
219
  requirements:
200
220
  - - "~>"
201
221
  - !ruby/object:Gem::Version
202
222
  version: '0.7'
203
223
  - !ruby/object:Gem::Dependency
224
+ name: grape
204
225
  requirement: !ruby/object:Gem::Requirement
205
226
  requirements:
206
227
  - - ">="
@@ -209,9 +230,8 @@ dependencies:
209
230
  - - "<"
210
231
  - !ruby/object:Gem::Version
211
232
  version: 0.19.1
212
- name: grape
213
- prerelease: false
214
233
  type: :development
234
+ prerelease: false
215
235
  version_requirements: !ruby/object:Gem::Requirement
216
236
  requirements:
217
237
  - - ">="
@@ -221,20 +241,21 @@ dependencies:
221
241
  - !ruby/object:Gem::Version
222
242
  version: 0.19.1
223
243
  - !ruby/object:Gem::Dependency
244
+ name: json_schema
224
245
  requirement: !ruby/object:Gem::Requirement
225
246
  requirements:
226
247
  - - ">="
227
248
  - !ruby/object:Gem::Version
228
249
  version: '0'
229
- name: json_schema
230
- prerelease: false
231
250
  type: :development
251
+ prerelease: false
232
252
  version_requirements: !ruby/object:Gem::Requirement
233
253
  requirements:
234
254
  - - ">="
235
255
  - !ruby/object:Gem::Version
236
256
  version: '0'
237
257
  - !ruby/object:Gem::Dependency
258
+ name: rake
238
259
  requirement: !ruby/object:Gem::Requirement
239
260
  requirements:
240
261
  - - ">="
@@ -243,9 +264,8 @@ dependencies:
243
264
  - - "<"
244
265
  - !ruby/object:Gem::Version
245
266
  version: '12.0'
246
- name: rake
247
- prerelease: false
248
267
  type: :development
268
+ prerelease: false
249
269
  version_requirements: !ruby/object:Gem::Requirement
250
270
  requirements:
251
271
  - - ">="
@@ -333,6 +353,7 @@ files:
333
353
  - lib/active_model/serializer/has_many_reflection.rb
334
354
  - lib/active_model/serializer/has_one_reflection.rb
335
355
  - lib/active_model/serializer/lazy_association.rb
356
+ - lib/active_model/serializer/link.rb
336
357
  - lib/active_model/serializer/lint.rb
337
358
  - lib/active_model/serializer/null.rb
338
359
  - lib/active_model/serializer/reflection.rb
@@ -478,7 +499,7 @@ homepage: https://github.com/rails-api/active_model_serializers
478
499
  licenses:
479
500
  - MIT
480
501
  metadata: {}
481
- post_install_message:
502
+ post_install_message:
482
503
  rdoc_options: []
483
504
  require_paths:
484
505
  - lib
@@ -493,9 +514,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
493
514
  - !ruby/object:Gem::Version
494
515
  version: '0'
495
516
  requirements: []
496
- rubyforge_project:
497
- rubygems_version: 2.6.13
498
- signing_key:
517
+ rubyforge_project:
518
+ rubygems_version: 2.7.6
519
+ signing_key:
499
520
  specification_version: 4
500
521
  summary: Conventions-based JSON generation for Rails.
501
522
  test_files: