active_model_serializers 0.10.0.rc2 → 0.10.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
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