active_model_serializers 0.8.3 → 0.10.0.rc1

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +19 -20
  4. data/CHANGELOG.md +8 -67
  5. data/CONTRIBUTING.md +31 -0
  6. data/Gemfile +14 -1
  7. data/{MIT-LICENSE.txt → LICENSE.txt} +3 -2
  8. data/README.md +166 -495
  9. data/Rakefile +6 -12
  10. data/active_model_serializers.gemspec +21 -19
  11. data/lib/action_controller/serialization.rb +28 -27
  12. data/lib/active_model/serializer/adapter/fragment_cache.rb +78 -0
  13. data/lib/active_model/serializer/adapter/json/fragment_cache.rb +15 -0
  14. data/lib/active_model/serializer/adapter/json.rb +52 -0
  15. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +22 -0
  16. data/lib/active_model/serializer/adapter/json_api.rb +152 -0
  17. data/lib/active_model/serializer/adapter/null.rb +11 -0
  18. data/lib/active_model/serializer/adapter.rb +87 -0
  19. data/lib/active_model/serializer/array_serializer.rb +32 -0
  20. data/lib/active_model/serializer/configuration.rb +13 -0
  21. data/lib/active_model/serializer/fieldset.rb +40 -0
  22. data/lib/active_model/{serializers → serializer}/version.rb +1 -1
  23. data/lib/active_model/serializer.rb +179 -436
  24. data/lib/active_model_serializers.rb +9 -86
  25. data/lib/generators/serializer/USAGE +0 -3
  26. data/lib/generators/serializer/serializer_generator.rb +1 -6
  27. data/lib/generators/serializer/templates/serializer.rb +2 -13
  28. data/test/action_controller/adapter_selector_test.rb +51 -0
  29. data/test/action_controller/explicit_serializer_test.rb +110 -0
  30. data/test/action_controller/json_api_linked_test.rb +173 -0
  31. data/test/{serialization_scope_name_test.rb → action_controller/serialization_scope_name_test.rb} +7 -11
  32. data/test/action_controller/serialization_test.rb +365 -0
  33. data/test/adapter/fragment_cache_test.rb +27 -0
  34. data/test/adapter/json/belongs_to_test.rb +41 -0
  35. data/test/adapter/json/collection_test.rb +59 -0
  36. data/test/adapter/json/has_many_test.rb +36 -0
  37. data/test/adapter/json_api/belongs_to_test.rb +147 -0
  38. data/test/adapter/json_api/collection_test.rb +89 -0
  39. data/test/adapter/json_api/has_many_embed_ids_test.rb +45 -0
  40. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +98 -0
  41. data/test/adapter/json_api/has_many_test.rb +106 -0
  42. data/test/adapter/json_api/has_one_test.rb +59 -0
  43. data/test/adapter/json_api/linked_test.rb +257 -0
  44. data/test/adapter/json_test.rb +34 -0
  45. data/test/adapter/null_test.rb +25 -0
  46. data/test/adapter_test.rb +43 -0
  47. data/test/array_serializer_test.rb +21 -67
  48. data/test/fixtures/poro.rb +206 -0
  49. data/test/serializers/adapter_for_test.rb +50 -0
  50. data/test/serializers/associations_test.rb +106 -0
  51. data/test/serializers/attribute_test.rb +23 -0
  52. data/test/serializers/attributes_test.rb +28 -0
  53. data/test/serializers/cache_test.rb +128 -0
  54. data/test/serializers/configuration_test.rb +15 -0
  55. data/test/serializers/fieldset_test.rb +26 -0
  56. data/test/{generators_test.rb → serializers/generators_test.rb} +1 -27
  57. data/test/serializers/meta_test.rb +78 -0
  58. data/test/serializers/options_test.rb +21 -0
  59. data/test/serializers/serializer_for_test.rb +56 -0
  60. data/test/serializers/urls_test.rb +26 -0
  61. data/test/test_helper.rb +22 -13
  62. metadata +101 -42
  63. data/DESIGN.textile +0 -586
  64. data/Gemfile.edge +0 -9
  65. data/bench/perf.rb +0 -43
  66. data/cruft.md +0 -19
  67. data/lib/active_model/array_serializer.rb +0 -104
  68. data/lib/active_model/serializer/associations.rb +0 -233
  69. data/lib/active_record/serializer_override.rb +0 -16
  70. data/lib/generators/resource_override.rb +0 -13
  71. data/test/association_test.rb +0 -592
  72. data/test/caching_test.rb +0 -96
  73. data/test/no_serialization_scope_test.rb +0 -34
  74. data/test/serialization_test.rb +0 -392
  75. data/test/serializer_support_test.rb +0 -51
  76. data/test/serializer_test.rb +0 -1465
  77. data/test/test_fakes.rb +0 -217
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class Adapter
6
+ class NullTest < Minitest::Test
7
+ def setup
8
+ profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
9
+ serializer = ProfileSerializer.new(profile)
10
+
11
+ @adapter = Null.new(serializer)
12
+ end
13
+
14
+ def test_serializable_hash
15
+ assert_equal({}, @adapter.serializable_hash)
16
+ end
17
+
18
+ def test_it_returns_empty_json
19
+ assert_equal('{}', @adapter.to_json)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,43 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class AdapterTest < Minitest::Test
6
+ def setup
7
+ profile = Profile.new
8
+ @serializer = ProfileSerializer.new(profile)
9
+ @adapter = ActiveModel::Serializer::Adapter.new(@serializer)
10
+ end
11
+
12
+ def test_serializable_hash_is_abstract_method
13
+ assert_raises(NotImplementedError) do
14
+ @adapter.serializable_hash(only: [:name])
15
+ end
16
+ end
17
+
18
+ def test_serializer
19
+ assert_equal @serializer, @adapter.serializer
20
+ end
21
+
22
+ def test_adapter_class_for_known_adapter
23
+ klass = ActiveModel::Serializer::Adapter.adapter_class(:json_api)
24
+ assert_equal ActiveModel::Serializer::Adapter::JsonApi, klass
25
+ end
26
+
27
+ def test_adapter_class_for_unknown_adapter
28
+ klass = ActiveModel::Serializer::Adapter.adapter_class(:json_simple)
29
+ assert_nil klass
30
+ end
31
+
32
+ def test_create_adapter
33
+ adapter = ActiveModel::Serializer::Adapter.create(@serializer)
34
+ assert_equal ActiveModel::Serializer::Adapter::Json, adapter.class
35
+ end
36
+
37
+ def test_create_adapter_with_override
38
+ adapter = ActiveModel::Serializer::Adapter.create(@serializer, { adapter: :json_api})
39
+ assert_equal ActiveModel::Serializer::Adapter::JsonApi, adapter.class
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,75 +1,29 @@
1
- require "test_helper"
2
- require "test_fakes"
1
+ require 'test_helper'
3
2
 
4
- class ArraySerializerTest < ActiveModel::TestCase
3
+ module ActiveModel
4
+ class Serializer
5
+ class ArraySerializerTest < Minitest::Test
6
+ def setup
7
+ @comment = Comment.new
8
+ @post = Post.new
9
+ @serializer = ArraySerializer.new([@comment, @post], {some: :options})
10
+ end
5
11
 
6
- def test_array_items_do_not_have_root
7
- array = [
8
- BasicActiveModel.new(:name => "First model"),
9
- BasicActiveModel.new(:name => "Second model")
10
- ]
11
- expected = { "root" => [
12
- { :name => "First model" },
13
- { :name => "Second model" }
14
- ] }
12
+ def test_respond_to_each
13
+ assert_respond_to @serializer, :each
14
+ end
15
15
 
16
- default_serializer = array.active_model_serializer.new(array, :root => "root")
17
- each_serializer = array.active_model_serializer.new(array, :root => "root", :each_serializer => BasicSerializer)
16
+ def test_each_object_should_be_serialized_with_appropriate_serializer
17
+ serializers = @serializer.to_a
18
18
 
19
- default_json = default_serializer.as_json
20
- each_json = each_serializer.as_json
19
+ assert_kind_of CommentSerializer, serializers.first
20
+ assert_kind_of Comment, serializers.first.object
21
21
 
22
- assert_equal(expected, default_json)
23
- assert_equal(expected, each_json)
24
- end
25
-
26
- # serialize different typed objects
27
- def test_array_serializer
28
- model = Model.new
29
- user = User.new
30
- comments = Comment.new(:title => "Comment1", :id => 1)
31
-
32
- array = [model, user, comments]
33
- serializer = array.active_model_serializer.new(array, :scope => {:scope => true})
34
- assert_equal([
35
- { :model => "Model" },
36
- { :last_name => "Valim", :ok => true, :first_name => "Jose", :scope => true },
37
- { :title => "Comment1" }
38
- ], serializer.as_json)
39
- end
40
-
41
- def test_array_serializer_with_root
42
- comment1 = Comment.new(:title => "Comment1", :id => 1)
43
- comment2 = Comment.new(:title => "Comment2", :id => 2)
44
-
45
- array = [ comment1, comment2 ]
46
-
47
- serializer = array.active_model_serializer.new(array, :root => :comments)
48
-
49
- assert_equal({ :comments => [
50
- { :title => "Comment1" },
51
- { :title => "Comment2" }
52
- ]}, serializer.as_json)
53
- end
54
-
55
- def test_array_serializer_with_hash
56
- hash = {:value => "something"}
57
- array = [hash]
58
- serializer = array.active_model_serializer.new(array, :root => :items)
59
- assert_equal({ :items => [ hash.as_json ]}, serializer.as_json)
60
- end
61
-
62
- def test_array_serializer_with_specified_seriailizer
63
- post1 = Post.new(:title => "Post1", :author => "Author1", :id => 1)
64
- post2 = Post.new(:title => "Post2", :author => "Author2", :id => 2)
65
-
66
- array = [ post1, post2 ]
67
-
68
- serializer = array.active_model_serializer.new array, :each_serializer => CustomPostSerializer
22
+ assert_kind_of PostSerializer, serializers.last
23
+ assert_kind_of Post, serializers.last.object
69
24
 
70
- assert_equal([
71
- { :title => "Post1" },
72
- { :title => "Post2" }
73
- ], serializer.as_json)
25
+ assert_equal serializers.last.custom_options[:some], :options
26
+ end
27
+ end
74
28
  end
75
29
  end
@@ -0,0 +1,206 @@
1
+ class Model
2
+ def initialize(hash={})
3
+ @attributes = hash
4
+ end
5
+
6
+ def cache_key
7
+ "#{self.class.name.downcase}/#{self.id}-#{self.updated_at}"
8
+ end
9
+
10
+ def updated_at
11
+ @attributes[:updated_at] ||= DateTime.now.to_time.to_i
12
+ end
13
+
14
+ def read_attribute_for_serialization(name)
15
+ if name == :id || name == 'id'
16
+ id
17
+ else
18
+ @attributes[name]
19
+ end
20
+ end
21
+
22
+ def id
23
+ @attributes[:id] || @attributes['id'] || object_id
24
+ end
25
+
26
+ def to_param
27
+ id
28
+ end
29
+
30
+ def method_missing(meth, *args)
31
+ if meth.to_s =~ /^(.*)=$/
32
+ @attributes[$1.to_sym] = args[0]
33
+ elsif @attributes.key?(meth)
34
+ @attributes[meth]
35
+ else
36
+ super
37
+ end
38
+ end
39
+ end
40
+
41
+ class Profile < Model
42
+ end
43
+
44
+ class ProfileSerializer < ActiveModel::Serializer
45
+ attributes :name, :description
46
+
47
+ urls :posts, :comments
48
+
49
+ def arguments_passed_in?
50
+ options[:my_options] == :accessible
51
+ end
52
+ end
53
+
54
+ class ProfilePreviewSerializer < ActiveModel::Serializer
55
+ attributes :name
56
+
57
+ urls :posts, :comments
58
+ end
59
+
60
+ Post = Class.new(Model)
61
+ Like = Class.new(Model)
62
+ Comment = Class.new(Model)
63
+ Author = Class.new(Model)
64
+ Bio = Class.new(Model)
65
+ Blog = Class.new(Model)
66
+ Role = Class.new(Model)
67
+ User = Class.new(Model)
68
+ Location = Class.new(Model)
69
+ Place = Class.new(Model)
70
+
71
+ module Spam; end
72
+ Spam::UnrelatedLink = Class.new(Model)
73
+
74
+ PostSerializer = Class.new(ActiveModel::Serializer) do
75
+ cache key:'post', expires_in: 0.1
76
+ attributes :id, :title, :body
77
+
78
+ has_many :comments
79
+ belongs_to :blog
80
+ belongs_to :author
81
+ url :comments
82
+
83
+ def blog
84
+ Blog.new(id: 999, name: "Custom blog")
85
+ end
86
+
87
+ def custom_options
88
+ options
89
+ end
90
+ end
91
+
92
+ SpammyPostSerializer = Class.new(ActiveModel::Serializer) do
93
+ attributes :id
94
+ has_many :related
95
+
96
+ def self.root_name
97
+ 'posts'
98
+ end
99
+ end
100
+
101
+ CommentSerializer = Class.new(ActiveModel::Serializer) do
102
+ cache expires_in: 1.day
103
+ attributes :id, :body
104
+
105
+ belongs_to :post
106
+ belongs_to :author
107
+
108
+ def custom_options
109
+ options
110
+ end
111
+ end
112
+
113
+ AuthorSerializer = Class.new(ActiveModel::Serializer) do
114
+ cache key:'writer'
115
+ attributes :id, :name
116
+
117
+ has_many :posts, embed: :ids
118
+ has_many :roles, embed: :ids
119
+ has_one :bio
120
+ end
121
+
122
+ RoleSerializer = Class.new(ActiveModel::Serializer) do
123
+ cache only: [:name]
124
+ attributes :id, :name, :description, :slug
125
+
126
+ def slug
127
+ "#{name}-#{id}"
128
+ end
129
+
130
+ belongs_to :author
131
+ end
132
+
133
+ LikeSerializer = Class.new(ActiveModel::Serializer) do
134
+ attributes :id, :time
135
+
136
+ belongs_to :post
137
+ end
138
+
139
+ LocationSerializer = Class.new(ActiveModel::Serializer) do
140
+ cache only: [:place]
141
+ attributes :id, :lat, :lng
142
+
143
+ belongs_to :place
144
+
145
+ def place
146
+ 'Nowhere'
147
+ end
148
+ end
149
+
150
+ PlaceSerializer = Class.new(ActiveModel::Serializer) do
151
+ attributes :id, :name
152
+
153
+ has_many :locations
154
+ end
155
+
156
+ BioSerializer = Class.new(ActiveModel::Serializer) do
157
+ cache except: [:content]
158
+ attributes :id, :content, :rating
159
+
160
+ belongs_to :author
161
+ end
162
+
163
+ BlogSerializer = Class.new(ActiveModel::Serializer) do
164
+ attributes :id, :name
165
+
166
+ belongs_to :writer
167
+ has_many :articles
168
+ end
169
+
170
+ PaginatedSerializer = Class.new(ActiveModel::Serializer::ArraySerializer) do
171
+ def json_key
172
+ 'paginated'
173
+ end
174
+ end
175
+
176
+ AlternateBlogSerializer = Class.new(ActiveModel::Serializer) do
177
+ attribute :id
178
+ attribute :name, key: :title
179
+ end
180
+
181
+ CommentPreviewSerializer = Class.new(ActiveModel::Serializer) do
182
+ attributes :id
183
+
184
+ belongs_to :post
185
+ end
186
+
187
+ AuthorPreviewSerializer = Class.new(ActiveModel::Serializer) do
188
+ attributes :id
189
+
190
+ has_many :posts
191
+ end
192
+
193
+ PostPreviewSerializer = Class.new(ActiveModel::Serializer) do
194
+ def self.root_name
195
+ 'posts'
196
+ end
197
+
198
+ attributes :title, :body, :id
199
+
200
+ has_many :comments, serializer: CommentPreviewSerializer
201
+ belongs_to :author, serializer: AuthorPreviewSerializer
202
+ end
203
+
204
+ Spam::UnrelatedLinkSerializer = Class.new(ActiveModel::Serializer) do
205
+ attributes :id
206
+ end
@@ -0,0 +1,50 @@
1
+ module ActiveModel
2
+ class Serializer
3
+ class AdapterForTest < Minitest::Test
4
+ def setup
5
+ @previous_adapter = ActiveModel::Serializer.config.adapter
6
+ end
7
+
8
+ def teardown
9
+ ActiveModel::Serializer.config.adapter = @previous_adapter
10
+ end
11
+
12
+ def test_returns_default_adapter
13
+ adapter = ActiveModel::Serializer.adapter
14
+ assert_equal ActiveModel::Serializer::Adapter::Json, adapter
15
+ end
16
+
17
+ def test_overwrite_adapter_with_symbol
18
+ ActiveModel::Serializer.config.adapter = :null
19
+
20
+ adapter = ActiveModel::Serializer.adapter
21
+ assert_equal ActiveModel::Serializer::Adapter::Null, adapter
22
+ ensure
23
+
24
+ end
25
+
26
+ def test_overwrite_adapter_with_class
27
+ ActiveModel::Serializer.config.adapter = ActiveModel::Serializer::Adapter::Null
28
+
29
+ adapter = ActiveModel::Serializer.adapter
30
+ assert_equal ActiveModel::Serializer::Adapter::Null, adapter
31
+ end
32
+
33
+ def test_raises_exception_if_invalid_symbol_given
34
+ ActiveModel::Serializer.config.adapter = :unknown
35
+
36
+ assert_raises ArgumentError do
37
+ ActiveModel::Serializer.adapter
38
+ end
39
+ end
40
+
41
+ def test_raises_exception_if_it_does_not_know_hot_to_infer_adapter
42
+ ActiveModel::Serializer.config.adapter = 42
43
+
44
+ assert_raises ArgumentError do
45
+ ActiveModel::Serializer.adapter
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,106 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class AssociationsTest < Minitest::Test
6
+ class Model
7
+ def initialize(hash={})
8
+ @attributes = hash
9
+ end
10
+
11
+ def read_attribute_for_serialization(name)
12
+ @attributes[name]
13
+ end
14
+
15
+ def method_missing(meth, *args)
16
+ if meth.to_s =~ /^(.*)=$/
17
+ @attributes[$1.to_sym] = args[0]
18
+ elsif @attributes.key?(meth)
19
+ @attributes[meth]
20
+ else
21
+ super
22
+ end
23
+ end
24
+ end
25
+
26
+ def setup
27
+ @author = Author.new(name: 'Steve K.')
28
+ @author.bio = nil
29
+ @author.roles = []
30
+ @blog = Blog.new({ name: 'AMS Blog' })
31
+ @post = Post.new({ title: 'New Post', body: 'Body' })
32
+ @comment = Comment.new({ id: 1, body: 'ZOMG A COMMENT' })
33
+ @post.comments = [@comment]
34
+ @post.blog = @blog
35
+ @comment.post = @post
36
+ @comment.author = nil
37
+ @post.author = @author
38
+ @author.posts = [@post]
39
+
40
+ @post_serializer = PostSerializer.new(@post, {custom_options: true})
41
+ @author_serializer = AuthorSerializer.new(@author)
42
+ @comment_serializer = CommentSerializer.new(@comment)
43
+ end
44
+
45
+ def test_has_many_and_has_one
46
+ assert_equal(
47
+ { posts: { type: :has_many, association_options: { embed: :ids } },
48
+ roles: { type: :has_many, association_options: { embed: :ids } },
49
+ bio: { type: :has_one, association_options: {} } },
50
+ @author_serializer.class._associations
51
+ )
52
+ @author_serializer.each_association do |name, serializer, options|
53
+ if name == :posts
54
+ assert_equal({embed: :ids}, options)
55
+ assert_kind_of(ActiveModel::Serializer.config.array_serializer, serializer)
56
+ elsif name == :bio
57
+ assert_equal({}, options)
58
+ assert_nil serializer
59
+ elsif name == :roles
60
+ assert_equal({embed: :ids}, options)
61
+ assert_kind_of(ActiveModel::Serializer.config.array_serializer, serializer)
62
+ else
63
+ flunk "Unknown association: #{name}"
64
+ end
65
+ end
66
+ end
67
+
68
+ def test_serializer_options_are_passed_into_associations_serializers
69
+ @post_serializer.each_association do |name, association|
70
+ if name == :comments
71
+ assert association.first.custom_options[:custom_options]
72
+ end
73
+ end
74
+ end
75
+
76
+ def test_belongs_to
77
+ assert_equal(
78
+ { post: { type: :belongs_to, association_options: {} },
79
+ author: { type: :belongs_to, association_options: {} } },
80
+ @comment_serializer.class._associations
81
+ )
82
+ @comment_serializer.each_association do |name, serializer, options|
83
+ if name == :post
84
+ assert_equal({}, options)
85
+ assert_kind_of(PostSerializer, serializer)
86
+ elsif name == :author
87
+ assert_equal({}, options)
88
+ assert_nil serializer
89
+ else
90
+ flunk "Unknown association: #{name}"
91
+ end
92
+ end
93
+ end
94
+
95
+ def test_belongs_to_with_custom_method
96
+ blog_is_present = false
97
+
98
+ @post_serializer.each_association do |name, serializer, options|
99
+ blog_is_present = true if name == :blog
100
+ end
101
+
102
+ assert blog_is_present
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class AttributeTest < Minitest::Test
6
+ def setup
7
+ @blog = Blog.new({ id: 1, name: 'AMS Hints' })
8
+ @blog_serializer = AlternateBlogSerializer.new(@blog)
9
+ end
10
+
11
+ def test_attributes_definition
12
+ assert_equal([:id, :title],
13
+ @blog_serializer.class._attributes)
14
+ end
15
+
16
+ def test_json_serializable_hash
17
+ adapter = ActiveModel::Serializer::Adapter::Json.new(@blog_serializer)
18
+ assert_equal({:id=>1, :title=>"AMS Hints"}, adapter.serializable_hash)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class AttributesTest < Minitest::Test
6
+ def setup
7
+ @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
8
+ @profile_serializer = ProfileSerializer.new(@profile)
9
+ end
10
+
11
+ def test_attributes_definition
12
+ assert_equal([:name, :description],
13
+ @profile_serializer.class._attributes)
14
+ end
15
+
16
+ def test_attributes_with_fields_option
17
+ assert_equal({name: 'Name 1'},
18
+ @profile_serializer.attributes(fields: [:name]))
19
+ end
20
+
21
+ def test_required_fields
22
+ assert_equal({name: 'Name 1', description: 'Description 1'},
23
+ @profile_serializer.attributes(fields: [:name, :description], required_fields: [:name]))
24
+
25
+ end
26
+ end
27
+ end
28
+ end