active_model_serializers 0.10.0.rc2 → 0.10.0.rc3

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +82 -0
  4. data/.rubocop_todo.yml +315 -0
  5. data/.simplecov +99 -0
  6. data/.travis.yml +8 -0
  7. data/CHANGELOG.md +9 -3
  8. data/Gemfile +39 -8
  9. data/README.md +55 -31
  10. data/Rakefile +29 -2
  11. data/active_model_serializers.gemspec +37 -13
  12. data/appveyor.yml +25 -0
  13. data/docs/README.md +29 -0
  14. data/docs/general/adapters.md +110 -0
  15. data/docs/general/configuration_options.md +11 -0
  16. data/docs/general/getting_started.md +73 -0
  17. data/docs/howto/add_pagination_links.md +112 -0
  18. data/docs/howto/add_root_key.md +51 -0
  19. data/docs/howto/outside_controller_use.md +42 -0
  20. data/lib/action_controller/serialization.rb +24 -33
  21. data/lib/active_model/serializable_resource.rb +70 -0
  22. data/lib/active_model/serializer.rb +50 -131
  23. data/lib/active_model/serializer/adapter.rb +84 -21
  24. data/lib/active_model/serializer/adapter/flatten_json.rb +9 -9
  25. data/lib/active_model/serializer/adapter/fragment_cache.rb +10 -13
  26. data/lib/active_model/serializer/adapter/json.rb +25 -28
  27. data/lib/active_model/serializer/adapter/json/fragment_cache.rb +2 -12
  28. data/lib/active_model/serializer/adapter/json_api.rb +100 -98
  29. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +4 -14
  30. data/lib/active_model/serializer/adapter/json_api/pagination_links.rb +50 -0
  31. data/lib/active_model/serializer/adapter/null.rb +2 -8
  32. data/lib/active_model/serializer/array_serializer.rb +22 -17
  33. data/lib/active_model/serializer/association.rb +20 -0
  34. data/lib/active_model/serializer/associations.rb +97 -0
  35. data/lib/active_model/serializer/belongs_to_reflection.rb +10 -0
  36. data/lib/active_model/serializer/collection_reflection.rb +7 -0
  37. data/lib/active_model/serializer/configuration.rb +1 -0
  38. data/lib/active_model/serializer/fieldset.rb +7 -7
  39. data/lib/active_model/serializer/has_many_reflection.rb +10 -0
  40. data/lib/active_model/serializer/has_one_reflection.rb +10 -0
  41. data/lib/active_model/serializer/lint.rb +129 -0
  42. data/lib/active_model/serializer/railtie.rb +7 -0
  43. data/lib/active_model/serializer/reflection.rb +74 -0
  44. data/lib/active_model/serializer/singular_reflection.rb +7 -0
  45. data/lib/active_model/serializer/utils.rb +35 -0
  46. data/lib/active_model/serializer/version.rb +1 -1
  47. data/lib/active_model_serializers.rb +28 -14
  48. data/lib/generators/serializer/serializer_generator.rb +7 -7
  49. data/lib/generators/serializer/templates/{serializer.rb → serializer.rb.erb} +2 -2
  50. data/lib/tasks/rubocop.rake +0 -0
  51. data/test/action_controller/adapter_selector_test.rb +3 -3
  52. data/test/action_controller/explicit_serializer_test.rb +9 -9
  53. data/test/action_controller/json_api/linked_test.rb +179 -0
  54. data/test/action_controller/json_api/pagination_test.rb +116 -0
  55. data/test/action_controller/serialization_scope_name_test.rb +10 -6
  56. data/test/action_controller/serialization_test.rb +149 -112
  57. data/test/active_record_test.rb +9 -0
  58. data/test/adapter/fragment_cache_test.rb +11 -1
  59. data/test/adapter/json/belongs_to_test.rb +4 -5
  60. data/test/adapter/json/collection_test.rb +30 -21
  61. data/test/adapter/json/has_many_test.rb +20 -9
  62. data/test/adapter/json_api/belongs_to_test.rb +38 -38
  63. data/test/adapter/json_api/collection_test.rb +22 -23
  64. data/test/adapter/json_api/has_many_embed_ids_test.rb +2 -2
  65. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +4 -4
  66. data/test/adapter/json_api/has_many_test.rb +54 -19
  67. data/test/adapter/json_api/has_one_test.rb +28 -8
  68. data/test/adapter/json_api/json_api_test.rb +37 -0
  69. data/test/adapter/json_api/linked_test.rb +75 -75
  70. data/test/adapter/json_api/pagination_links_test.rb +115 -0
  71. data/test/adapter/json_api/resource_type_config_test.rb +59 -0
  72. data/test/adapter/json_test.rb +18 -5
  73. data/test/adapter_test.rb +10 -11
  74. data/test/array_serializer_test.rb +63 -5
  75. data/test/capture_warnings.rb +65 -0
  76. data/test/fixtures/active_record.rb +56 -0
  77. data/test/fixtures/poro.rb +60 -29
  78. data/test/generators/scaffold_controller_generator_test.rb +1 -2
  79. data/test/generators/serializer_generator_test.rb +17 -12
  80. data/test/lint_test.rb +37 -0
  81. data/test/logger_test.rb +18 -0
  82. data/test/poro_test.rb +9 -0
  83. data/test/serializable_resource_test.rb +27 -0
  84. data/test/serializers/adapter_for_test.rb +123 -3
  85. data/test/serializers/association_macros_test.rb +36 -0
  86. data/test/serializers/associations_test.rb +70 -47
  87. data/test/serializers/attribute_test.rb +28 -4
  88. data/test/serializers/attributes_test.rb +8 -14
  89. data/test/serializers/cache_test.rb +58 -31
  90. data/test/serializers/fieldset_test.rb +3 -4
  91. data/test/serializers/meta_test.rb +42 -28
  92. data/test/serializers/root_test.rb +21 -0
  93. data/test/serializers/serializer_for_test.rb +1 -1
  94. data/test/support/rails_app.rb +21 -0
  95. data/test/support/serialization_testing.rb +13 -0
  96. data/test/support/simplecov.rb +6 -0
  97. data/test/support/stream_capture.rb +50 -0
  98. data/test/support/test_case.rb +5 -0
  99. data/test/test_helper.rb +41 -29
  100. data/test/utils/include_args_to_hash_test.rb +79 -0
  101. metadata +123 -17
  102. data/test/action_controller/json_api_linked_test.rb +0 -179
  103. data/test/action_controller/rescue_from_test.rb +0 -32
  104. data/test/serializers/urls_test.rb +0 -26
@@ -3,12 +3,11 @@ require 'test_helper'
3
3
  module ActiveModel
4
4
  class Serializer
5
5
  class FieldsetTest < Minitest::Test
6
-
7
6
  def test_fieldset_with_hash
8
- fieldset = ActiveModel::Serializer::Fieldset.new({'post' => ['id', 'title'], 'coment' => ['body']})
7
+ fieldset = ActiveModel::Serializer::Fieldset.new({ 'post' => %w(id title), 'coment' => ['body'] })
9
8
 
10
9
  assert_equal(
11
- {:post=>[:id, :title], :coment=>[:body]},
10
+ { :post => [:id, :title], :coment => [:body] },
12
11
  fieldset.fields
13
12
  )
14
13
  end
@@ -17,7 +16,7 @@ module ActiveModel
17
16
  fieldset = ActiveModel::Serializer::Fieldset.new(['title'], 'post')
18
17
 
19
18
  assert_equal(
20
- {:post => [:title]},
19
+ { :post => [:title] },
21
20
  fieldset.fields
22
21
  )
23
22
  end
@@ -7,19 +7,19 @@ module ActiveModel
7
7
  ActionController::Base.cache_store.clear
8
8
  @blog = Blog.new(id: 1,
9
9
  name: 'AMS Hints',
10
- writer: Author.new(id: 2, name: "Steve"),
11
- articles: [Post.new(id: 3, title: "AMS")])
10
+ writer: Author.new(id: 2, name: 'Steve'),
11
+ articles: [Post.new(id: 3, title: 'AMS')])
12
12
  end
13
13
 
14
14
  def test_meta_is_present_with_root
15
- serializer = AlternateBlogSerializer.new(@blog, meta: {total: 10})
16
- adapter = ActiveModel::Serializer::Adapter::Json.new(serializer, root: 'blog')
15
+ serializer = AlternateBlogSerializer.new(@blog, meta: { total: 10 })
16
+ adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
17
17
  expected = {
18
- alternate_blog: {
18
+ blog: {
19
19
  id: 1,
20
- title: "AMS Hints"
20
+ title: 'AMS Hints'
21
21
  },
22
- "meta" => {
22
+ 'meta' => {
23
23
  total: 10
24
24
  }
25
25
  }
@@ -27,42 +27,58 @@ module ActiveModel
27
27
  end
28
28
 
29
29
  def test_meta_is_not_included_when_root_is_missing
30
- adapter = load_adapter(meta: {total: 10})
30
+ # load_adapter uses FlattenJson Adapter
31
+ adapter = load_adapter(meta: { total: 10 })
31
32
  expected = {
32
33
  id: 1,
33
- title: "AMS Hints"
34
+ title: 'AMS Hints'
34
35
  }
35
36
  assert_equal expected, adapter.as_json
36
37
  end
37
38
 
38
39
  def test_meta_key_is_used
39
- serializer = AlternateBlogSerializer.new(@blog, root: 'blog', meta: {total: 10}, meta_key: "haha_meta")
40
- adapter = ActiveModel::Serializer::Adapter::Json.new(serializer, root: 'blog')
40
+ serializer = AlternateBlogSerializer.new(@blog, meta: { total: 10 }, meta_key: 'haha_meta')
41
+ adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
41
42
  expected = {
42
- alternate_blog: {
43
+ blog: {
43
44
  id: 1,
44
- title: "AMS Hints"
45
+ title: 'AMS Hints'
45
46
  },
46
- "haha_meta" => {
47
+ 'haha_meta' => {
47
48
  total: 10
48
49
  }
49
50
  }
50
51
  assert_equal expected, adapter.as_json
51
52
  end
52
53
 
54
+ def test_meta_key_is_used_with_json_api
55
+ serializer = AlternateBlogSerializer.new(@blog, meta: { total: 10 }, meta_key: 'haha_meta')
56
+ adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
57
+ expected = {
58
+ data: {
59
+ id: '1',
60
+ type: 'blogs',
61
+ attributes: { title: 'AMS Hints' }
62
+ },
63
+ 'haha_meta' => { total: 10 }
64
+ }
65
+ assert_equal expected, adapter.as_json
66
+ end
67
+
53
68
  def test_meta_is_not_present_on_arrays_without_root
54
- serializer = ArraySerializer.new([@blog], meta: {total: 10})
69
+ serializer = ArraySerializer.new([@blog], meta: { total: 10 })
70
+ # FlattenJSON doesn't have support to root
55
71
  adapter = ActiveModel::Serializer::Adapter::FlattenJson.new(serializer)
56
72
  expected = [{
57
73
  id: 1,
58
- name: "AMS Hints",
74
+ name: 'AMS Hints',
59
75
  writer: {
60
76
  id: 2,
61
- name: "Steve"
77
+ name: 'Steve'
62
78
  },
63
79
  articles: [{
64
80
  id: 3,
65
- title: "AMS",
81
+ title: 'AMS',
66
82
  body: nil
67
83
  }]
68
84
  }]
@@ -70,19 +86,20 @@ module ActiveModel
70
86
  end
71
87
 
72
88
  def test_meta_is_present_on_arrays_with_root
73
- serializer = ArraySerializer.new([@blog], meta: {total: 10}, meta_key: "haha_meta")
74
- adapter = ActiveModel::Serializer::Adapter::Json.new(serializer, root: 'blog')
89
+ serializer = ArraySerializer.new([@blog], meta: { total: 10 }, meta_key: 'haha_meta')
90
+ # JSON adapter adds root by default
91
+ adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
75
92
  expected = {
76
93
  blogs: [{
77
94
  id: 1,
78
- name: "AMS Hints",
95
+ name: 'AMS Hints',
79
96
  writer: {
80
97
  id: 2,
81
- name: "Steve"
98
+ name: 'Steve'
82
99
  },
83
100
  articles: [{
84
101
  id: 3,
85
- title: "AMS",
102
+ title: 'AMS',
86
103
  body: nil
87
104
  }]
88
105
  }],
@@ -96,11 +113,8 @@ module ActiveModel
96
113
  private
97
114
 
98
115
  def load_adapter(options)
99
- adapter_opts, serializer_opts =
100
- options.partition { |k, _| ActionController::Serialization::ADAPTER_OPTION_KEYS.include? k }.map { |h| Hash[h] }
101
-
102
- serializer = AlternateBlogSerializer.new(@blog, serializer_opts)
103
- ActiveModel::Serializer::Adapter::FlattenJson.new(serializer, adapter_opts)
116
+ options = options.merge(adapter: :flatten_json, serializer: AlternateBlogSerializer)
117
+ ActiveModel::SerializableResource.new(@blog, options)
104
118
  end
105
119
  end
106
120
  end
@@ -0,0 +1,21 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class RootTest < Minitest::Test
6
+ def setup
7
+ @virtual_value = VirtualValue.new(id: 1)
8
+ end
9
+
10
+ def test_overwrite_root
11
+ serializer = VirtualValueSerializer.new(@virtual_value, { root: 'smth' })
12
+ assert_equal('smth', serializer.json_key)
13
+ end
14
+
15
+ def test_underscore_in_root
16
+ serializer = VirtualValueSerializer.new(@virtual_value)
17
+ assert_equal('virtual_value', serializer.json_key)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -26,7 +26,7 @@ module ActiveModel
26
26
  end
27
27
  end
28
28
 
29
- class SerializerTest < Minitest::Test
29
+ class SerializerTest < Minitest::Test
30
30
  class MyProfile < Profile
31
31
  end
32
32
  class CustomProfile
@@ -0,0 +1,21 @@
1
+ class Foo < Rails::Application
2
+ if Rails::VERSION::MAJOR >= 4
3
+ config.eager_load = false
4
+ config.secret_key_base = 'abc123'
5
+ config.action_controller.perform_caching = true
6
+ config.active_support.test_order = :random
7
+ config.logger = Logger.new(nil)
8
+ ActionController::Base.cache_store = :memory_store
9
+ end
10
+ end
11
+ Foo.initialize!
12
+
13
+ module TestHelper
14
+ Routes = ActionDispatch::Routing::RouteSet.new
15
+ Routes.draw do
16
+ get ':controller(/:action(/:id))'
17
+ get ':controller(/:action)'
18
+ end
19
+
20
+ ActionController::Base.send :include, Routes.url_helpers
21
+ end
@@ -0,0 +1,13 @@
1
+ class Minitest::Test
2
+ def before_setup
3
+ ActionController::Base.cache_store.clear
4
+ end
5
+
6
+ def with_adapter(adapter)
7
+ old_adapter = ActiveModel::Serializer.config.adapter
8
+ ActiveModel::Serializer.config.adapter = adapter
9
+ yield
10
+ ensure
11
+ ActiveModel::Serializer.config.adapter = old_adapter
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ # https://github.com/colszowka/simplecov/pull/400
2
+ # https://github.com/ruby/ruby/blob/trunk/lib/English.rb
3
+ unless defined?(English)
4
+ # The exception object passed to +raise+.
5
+ alias $ERROR_INFO $! # rubocop:disable Style/SpecialGlobalVars
6
+ end
@@ -0,0 +1,50 @@
1
+ # Use cleaner stream testing interface from Rails 5 if available
2
+ # see https://github.com/rails/rails/blob/29959eb59d/activesupport/lib/active_support/testing/stream.rb
3
+ begin
4
+ require 'active_support/testing/stream'
5
+ rescue LoadError
6
+ require 'tempfile'
7
+ module ActiveSupport
8
+ module Testing
9
+ module Stream #:nodoc:
10
+ private
11
+
12
+ def silence_stream(stream)
13
+ old_stream = stream.dup
14
+ stream.reopen(IO::NULL)
15
+ stream.sync = true
16
+ yield
17
+ ensure
18
+ stream.reopen(old_stream)
19
+ old_stream.close
20
+ end
21
+
22
+ def quietly
23
+ silence_stream(STDOUT) do
24
+ silence_stream(STDERR) do
25
+ yield
26
+ end
27
+ end
28
+ end
29
+
30
+ def capture(stream)
31
+ stream = stream.to_s
32
+ captured_stream = Tempfile.new(stream)
33
+ stream_io = eval("$#{stream}") # rubocop:disable Lint/Eval
34
+ origin_stream = stream_io.dup
35
+ stream_io.reopen(captured_stream)
36
+
37
+ yield
38
+
39
+ stream_io.rewind
40
+ return captured_stream.read
41
+ ensure
42
+ captured_stream.close
43
+ captured_stream.unlink
44
+ stream_io.reopen(origin_stream)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,5 @@
1
+ ActionController::TestCase.class_eval do
2
+ def setup
3
+ @routes = TestHelper::Routes
4
+ end
5
+ end
data/test/test_helper.rb CHANGED
@@ -1,44 +1,56 @@
1
1
  require 'bundler/setup'
2
2
 
3
+ begin
4
+ require 'simplecov'
5
+ # HACK: till https://github.com/colszowka/simplecov/pull/400 is merged and released.
6
+ # Otherwise you may get:
7
+ # simplecov-0.10.0/lib/simplecov/defaults.rb:50: warning: global variable `$ERROR_INFO' not initialized
8
+ require 'support/simplecov'
9
+ AppCoverage.start
10
+ rescue LoadError
11
+ STDERR.puts 'Running without SimpleCov'
12
+ end
13
+
14
+ require 'timecop'
3
15
  require 'rails'
4
16
  require 'action_controller'
5
17
  require 'action_controller/test_case'
6
18
  require 'action_controller/railtie'
7
19
  require 'active_support/json'
8
- require 'minitest/autorun'
9
20
  require 'fileutils'
10
- # Ensure backward compatibility with Minitest 4
11
- Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
12
-
13
- require 'active_model_serializers'
21
+ FileUtils.mkdir_p(File.expand_path('../../tmp/cache', __FILE__))
14
22
 
15
- class Foo < Rails::Application
16
- if Rails::VERSION::MAJOR >= 4
17
- config.eager_load = false
18
- config.secret_key_base = 'abc123'
19
- config.action_controller.perform_caching = true
20
- config.active_support.test_order = :random
21
- config.logger = Logger.new(nil)
22
- ActionController::Base.cache_store = :memory_store
23
+ gem 'minitest'
24
+ require 'minitest/autorun'
25
+ if defined?(Minitest::Test)
26
+ # Minitest 5
27
+ # https://github.com/seattlerb/minitest/blob/e21fdda9d/lib/minitest/autorun.rb
28
+ # https://github.com/seattlerb/minitest/blob/e21fdda9d/lib/minitest.rb#L45-L59
29
+ else
30
+ # Minitest 4
31
+ # https://github.com/seattlerb/minitest/blob/644a52fd0/lib/minitest/autorun.rb
32
+ # https://github.com/seattlerb/minitest/blob/644a52fd0/lib/minitest/unit.rb#L768-L787
33
+ # Ensure backward compatibility with Minitest 4
34
+ Minitest = MiniTest unless defined?(Minitest)
35
+ Minitest::Test = MiniTest::Unit::TestCase
36
+ def Minitest.after_run(&block)
37
+ MiniTest::Unit.after_tests(&block)
23
38
  end
24
39
  end
25
- FileUtils.mkdir_p(File.expand_path('../../tmp/cache', __FILE__))
26
- Foo.initialize!
27
40
 
28
- require 'fixtures/poro'
41
+ require 'capture_warnings'
42
+ CaptureWarnings.new(_fail_build = true).execute!
29
43
 
30
- module TestHelper
31
- Routes = ActionDispatch::Routing::RouteSet.new
32
- Routes.draw do
33
- get ':controller(/:action(/:id))'
34
- get ':controller(/:action)'
35
- end
44
+ require 'active_model_serializers'
36
45
 
37
- ActionController::Base.send :include, Routes.url_helpers
38
- end
46
+ require 'support/stream_capture'
39
47
 
40
- ActionController::TestCase.class_eval do
41
- def setup
42
- @routes = TestHelper::Routes
43
- end
44
- end
48
+ require 'support/rails_app'
49
+
50
+ require 'support/test_case'
51
+
52
+ require 'support/serialization_testing'
53
+
54
+ require 'fixtures/active_record'
55
+
56
+ require 'fixtures/poro'
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ module Utils
6
+ class IncludeArgsToHashTest < Minitest::Test
7
+ def test_nil
8
+ input = nil
9
+ expected = {}
10
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
11
+ assert_equal(expected, actual)
12
+ end
13
+
14
+ def test_empty_string
15
+ input = ''
16
+ expected = {}
17
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
18
+ assert_equal(expected, actual)
19
+ end
20
+
21
+ def test_single_string
22
+ input = 'author'
23
+ expected = { author: {} }
24
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
25
+ assert_equal(expected, actual)
26
+ end
27
+
28
+ def test_multiple_strings
29
+ input = 'author,comments'
30
+ expected = { author: {}, comments: {} }
31
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
32
+ assert_equal(expected, actual)
33
+ end
34
+
35
+ def test_multiple_strings_with_space
36
+ input = 'author, comments'
37
+ expected = { author: {}, comments: {} }
38
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
39
+ assert_equal(expected, actual)
40
+ end
41
+
42
+ def test_nested_string
43
+ input = 'posts.author'
44
+ expected = { posts: { author: {} } }
45
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
46
+ assert_equal(expected, actual)
47
+ end
48
+
49
+ def test_multiple_nested_string
50
+ input = 'posts.author,posts.comments.author,comments'
51
+ expected = { posts: { author: {}, comments: { author: {} } }, comments: {} }
52
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
53
+ assert_equal(expected, actual)
54
+ end
55
+
56
+ def test_empty_array
57
+ input = []
58
+ expected = {}
59
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
60
+ assert_equal(expected, actual)
61
+ end
62
+
63
+ def test_simple_array
64
+ input = [:comments, :author]
65
+ expected = { author: {}, comments: {} }
66
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
67
+ assert_equal(expected, actual)
68
+ end
69
+
70
+ def test_nested_array
71
+ input = [:comments, posts: [:author, comments: [:author]]]
72
+ expected = { posts: { author: {}, comments: { author: {} } }, comments: {} }
73
+ actual = ActiveModel::Serializer::Utils.include_args_to_hash(input)
74
+ assert_equal(expected, actual)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end