active_model_serializers 0.8.3 → 0.10.0.rc1

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