active_model_serializers 0.8.3 → 0.9.4

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +122 -5
  3. data/CONTRIBUTING.md +20 -0
  4. data/DESIGN.textile +4 -4
  5. data/{MIT-LICENSE.txt → MIT-LICENSE} +0 -0
  6. data/README.md +396 -95
  7. data/lib/action_controller/serialization.rb +50 -12
  8. data/lib/action_controller/serialization_test_case.rb +79 -0
  9. data/lib/active_model/array_serializer.rb +47 -78
  10. data/lib/active_model/default_serializer.rb +32 -0
  11. data/lib/active_model/serializable/utils.rb +16 -0
  12. data/lib/active_model/serializable.rb +62 -0
  13. data/lib/active_model/serializer/association/has_many.rb +39 -0
  14. data/lib/active_model/serializer/association/has_one.rb +25 -0
  15. data/lib/active_model/serializer/association.rb +58 -0
  16. data/lib/active_model/serializer/config.rb +31 -0
  17. data/lib/active_model/serializer/generators/resource_override.rb +13 -0
  18. data/lib/{generators → active_model/serializer/generators}/serializer/USAGE +0 -0
  19. data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +14 -0
  20. data/lib/active_model/serializer/generators/serializer/serializer_generator.rb +37 -0
  21. data/lib/active_model/serializer/generators/serializer/templates/controller.rb +93 -0
  22. data/lib/active_model/serializer/generators/serializer/templates/serializer.rb +8 -0
  23. data/lib/active_model/serializer/railtie.rb +18 -0
  24. data/lib/active_model/{serializers → serializer}/version.rb +1 -1
  25. data/lib/active_model/serializer.rb +214 -423
  26. data/lib/active_model/serializer_support.rb +5 -0
  27. data/lib/active_model_serializers/mime_types.rb +14 -0
  28. data/lib/active_model_serializers.rb +12 -87
  29. data/test/fixtures/active_record.rb +96 -0
  30. data/test/fixtures/poro.rb +187 -0
  31. data/test/fixtures/template.html.erb +1 -0
  32. data/test/integration/action_controller/namespaced_serialization_test.rb +105 -0
  33. data/test/integration/action_controller/serialization_test.rb +287 -0
  34. data/test/integration/action_controller/serialization_test_case_test.rb +71 -0
  35. data/test/integration/active_record/active_record_test.rb +94 -0
  36. data/test/integration/generators/resource_generator_test.rb +26 -0
  37. data/test/integration/generators/scaffold_controller_generator_test.rb +64 -0
  38. data/test/integration/generators/serializer_generator_test.rb +41 -0
  39. data/test/test_app.rb +14 -0
  40. data/test/test_helper.rb +10 -18
  41. data/test/unit/active_model/array_serializer/except_test.rb +18 -0
  42. data/test/unit/active_model/array_serializer/key_format_test.rb +18 -0
  43. data/test/unit/active_model/array_serializer/meta_test.rb +53 -0
  44. data/test/unit/active_model/array_serializer/only_test.rb +18 -0
  45. data/test/unit/active_model/array_serializer/options_test.rb +16 -0
  46. data/test/unit/active_model/array_serializer/root_test.rb +102 -0
  47. data/test/unit/active_model/array_serializer/scope_test.rb +24 -0
  48. data/test/unit/active_model/array_serializer/serialization_test.rb +216 -0
  49. data/test/unit/active_model/default_serializer_test.rb +13 -0
  50. data/test/unit/active_model/serializer/associations/build_serializer_test.rb +36 -0
  51. data/test/unit/active_model/serializer/associations_test.rb +19 -0
  52. data/test/unit/active_model/serializer/attributes_test.rb +57 -0
  53. data/test/unit/active_model/serializer/config_test.rb +91 -0
  54. data/test/unit/active_model/serializer/filter_test.rb +69 -0
  55. data/test/unit/active_model/serializer/has_many_polymorphic_test.rb +189 -0
  56. data/test/unit/active_model/serializer/has_many_test.rb +265 -0
  57. data/test/unit/active_model/serializer/has_one_and_has_many_test.rb +27 -0
  58. data/test/unit/active_model/serializer/has_one_polymorphic_test.rb +196 -0
  59. data/test/unit/active_model/serializer/has_one_test.rb +253 -0
  60. data/test/unit/active_model/serializer/key_format_test.rb +25 -0
  61. data/test/unit/active_model/serializer/meta_test.rb +39 -0
  62. data/test/unit/active_model/serializer/options_test.rb +42 -0
  63. data/test/unit/active_model/serializer/root_test.rb +117 -0
  64. data/test/unit/active_model/serializer/scope_test.rb +49 -0
  65. data/test/unit/active_model/serializer/url_helpers_test.rb +35 -0
  66. metadata +107 -64
  67. data/.gitignore +0 -18
  68. data/.travis.yml +0 -28
  69. data/Gemfile +0 -4
  70. data/Gemfile.edge +0 -9
  71. data/Rakefile +0 -18
  72. data/active_model_serializers.gemspec +0 -24
  73. data/bench/perf.rb +0 -43
  74. data/cruft.md +0 -19
  75. data/lib/active_model/serializer/associations.rb +0 -233
  76. data/lib/active_record/serializer_override.rb +0 -16
  77. data/lib/generators/resource_override.rb +0 -13
  78. data/lib/generators/serializer/serializer_generator.rb +0 -42
  79. data/lib/generators/serializer/templates/serializer.rb +0 -19
  80. data/test/array_serializer_test.rb +0 -75
  81. data/test/association_test.rb +0 -592
  82. data/test/caching_test.rb +0 -96
  83. data/test/generators_test.rb +0 -85
  84. data/test/no_serialization_scope_test.rb +0 -34
  85. data/test/serialization_scope_name_test.rb +0 -67
  86. data/test/serialization_test.rb +0 -392
  87. data/test/serializer_support_test.rb +0 -51
  88. data/test/serializer_test.rb +0 -1465
  89. data/test/test_fakes.rb +0 -217
@@ -0,0 +1,5 @@
1
+ module ActiveModel
2
+ module SerializerSupport
3
+ alias read_attribute_for_serialization send
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ # module ActiveModelSerializers::JSONAPI
2
+ # HEADERS = {
3
+ # content_type: { "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE }
4
+ # }
5
+ # MEDIA_TYPE = 'application/vnd.api+json'
6
+ # end
7
+ #
8
+ # Mime::Type.register ActiveModelSerializers::JSONAPI::MEDIA_TYPE, :api_json
9
+ #
10
+ # ActionDispatch::ParamsParser::DEFAULT_PARSERS[Mime::Type.lookup(ActiveModelSerializers::JSONAPI::MEDIA_TYPE)] = lambda do |body|
11
+ # data = JSON.parse(body)
12
+ # data = {:_json => data} unless data.is_a?(Hash)
13
+ # data.with_indifferent_access
14
+ # end
@@ -1,95 +1,20 @@
1
- require "active_support"
2
- require "active_support/core_ext/string/inflections"
3
- require "active_support/notifications"
4
- require "active_model"
5
- require "active_model/array_serializer"
6
- require "active_model/serializer"
7
- require "active_model/serializer/associations"
8
- require "set"
9
-
10
- if defined?(Rails)
11
- module ActiveModel
12
- class Railtie < Rails::Railtie
13
- generators do |app|
14
- app ||= Rails.application # Rails 3.0.x does not yield `app`
15
-
16
- Rails::Generators.configure!(app.config.generators)
17
- Rails::Generators.hidden_namespaces.uniq!
18
- require_relative "generators/resource_override"
19
- end
20
-
21
- initializer "include_routes.active_model_serializer" do |app|
22
- ActiveSupport.on_load(:active_model_serializers) do
23
- include app.routes.url_helpers
24
- end
25
- end
26
-
27
- initializer "caching.active_model_serializer" do |app|
28
- ActiveModel::Serializer.perform_caching = app.config.action_controller.perform_caching
29
- ActiveModel::ArraySerializer.perform_caching = app.config.action_controller.perform_caching
30
-
31
- ActiveModel::Serializer.cache = Rails.cache
32
- ActiveModel::ArraySerializer.cache = Rails.cache
33
- end
34
- end
35
- end
36
- end
37
-
38
- module ActiveModel::SerializerSupport
39
- extend ActiveSupport::Concern
40
-
41
- module ClassMethods #:nodoc:
42
- if "".respond_to?(:safe_constantize)
43
- def active_model_serializer
44
- "#{self.name}Serializer".safe_constantize
45
- end
46
- else
47
- def active_model_serializer
48
- begin
49
- "#{self.name}Serializer".constantize
50
- rescue NameError => e
51
- raise unless e.message =~ /uninitialized constant/
52
- end
53
- end
54
- end
55
- end
56
-
57
- # Returns a model serializer for this object considering its namespace.
58
- def active_model_serializer
59
- self.class.active_model_serializer
60
- end
61
-
62
- alias :read_attribute_for_serialization :send
63
- end
64
-
65
- module ActiveModel::ArraySerializerSupport
66
- def active_model_serializer
67
- ActiveModel::ArraySerializer
68
- end
69
- end
70
-
71
- Array.send(:include, ActiveModel::ArraySerializerSupport)
72
- Set.send(:include, ActiveModel::ArraySerializerSupport)
73
-
74
- {
75
- :active_record => 'ActiveRecord::Relation',
76
- :mongoid => 'Mongoid::Criteria'
77
- }.each do |orm, rel_class|
78
- ActiveSupport.on_load(orm) do
79
- include ActiveModel::SerializerSupport
80
- rel_class.constantize.send(:include, ActiveModel::ArraySerializerSupport)
81
- end
82
- end
1
+ require 'active_model'
2
+ require 'active_model/serializer'
3
+ require 'active_model/serializer_support'
4
+ require 'active_model/serializer/version'
5
+ require 'active_model/serializer/railtie' if defined?(Rails)
83
6
 
84
7
  begin
85
8
  require 'action_controller'
86
9
  require 'action_controller/serialization'
10
+ require 'action_controller/serialization_test_case'
87
11
 
88
12
  ActiveSupport.on_load(:action_controller) do
89
- include ::ActionController::Serialization
13
+ if ::ActionController::Serialization.enabled
14
+ ActionController::Base.send(:include, ::ActionController::Serialization)
15
+ ActionController::TestCase.send(:include, ::ActionController::SerializationAssertions)
16
+ end
90
17
  end
91
- rescue LoadError => ex
92
- # rails on installed, continuing
18
+ rescue LoadError
19
+ # rails not installed, continuing
93
20
  end
94
-
95
- ActiveSupport.run_load_hooks(:active_model_serializers, ActiveModel::Serializer)
@@ -0,0 +1,96 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Base.establish_connection(
4
+ :adapter => 'sqlite3',
5
+ :database => ':memory:'
6
+ )
7
+
8
+ ActiveRecord::Schema.define do
9
+ create_table :ar_posts, force: true do |t|
10
+ t.string :title
11
+ t.text :body
12
+ t.belongs_to :ar_section, index: true
13
+ t.timestamps
14
+ end
15
+
16
+ create_table :ar_comments, force: true do |t|
17
+ t.text :body
18
+ t.belongs_to :ar_post, index: true
19
+ t.timestamps
20
+ end
21
+
22
+ create_table :ar_tags, force: true do |t|
23
+ t.string :name
24
+ end
25
+
26
+ create_table :ar_sections, force: true do |t|
27
+ t.string :name
28
+ end
29
+
30
+ create_table :ar_posts_tags, force: true do |t|
31
+ t.references :ar_post, :ar_tag, index: true
32
+ end
33
+
34
+ create_table :ar_comments_tags, force: true do |t|
35
+ t.references :ar_comment, :ar_tag, index: true
36
+ end
37
+ end
38
+
39
+ class ARPost < ActiveRecord::Base
40
+ has_many :ar_comments, class_name: 'ARComment'
41
+ has_and_belongs_to_many :ar_tags, class_name: 'ARTag', join_table: :ar_posts_tags
42
+ belongs_to :ar_section, class_name: 'ARSection'
43
+ end
44
+
45
+ class ARComment < ActiveRecord::Base
46
+ belongs_to :ar_post, class_name: 'ARPost'
47
+ has_and_belongs_to_many :ar_tags, class_name: 'ARTag', join_table: :ar_comments_tags
48
+ end
49
+
50
+ class ARTag < ActiveRecord::Base
51
+ end
52
+
53
+ class ARSection < ActiveRecord::Base
54
+ end
55
+
56
+ class ARPostSerializer < ActiveModel::Serializer
57
+ attributes :title, :body
58
+
59
+ has_many :ar_comments, :ar_tags
60
+ has_one :ar_section
61
+ end
62
+
63
+ class ARCommentSerializer < ActiveModel::Serializer
64
+ attributes :body
65
+
66
+ has_many :ar_tags
67
+ end
68
+
69
+ class ARTagSerializer < ActiveModel::Serializer
70
+ attributes :name
71
+ end
72
+
73
+ class ARSectionSerializer < ActiveModel::Serializer
74
+ attributes 'name'
75
+ end
76
+
77
+ class AREmbeddedSerializer < ActiveModel::Serializer
78
+ has_many :ar_tags, :ar_comments
79
+ end
80
+
81
+ ARPost.create(title: 'New post',
82
+ body: 'A body!!!',
83
+ ar_section: ARSection.create(name: 'ruby')).tap do |post|
84
+
85
+ short_tag = post.ar_tags.create(name: 'short')
86
+ whiny_tag = post.ar_tags.create(name: 'whiny')
87
+ happy_tag = ARTag.create(name: 'happy')
88
+
89
+ post.ar_comments.create(body: 'what a dumb post').tap do |comment|
90
+ comment.ar_tags.concat happy_tag, whiny_tag
91
+ end
92
+
93
+ post.ar_comments.create(body: 'i liked it').tap do |comment|
94
+ comment.ar_tags.concat happy_tag, short_tag
95
+ end
96
+ end
@@ -0,0 +1,187 @@
1
+ class Model
2
+ def initialize(hash = {})
3
+ @attributes = hash
4
+ end
5
+
6
+ def read_attribute_for_serialization(name)
7
+ if name == :id || name == 'id'
8
+ object_id
9
+ elsif respond_to?(name)
10
+ send name
11
+ else
12
+ @attributes[name]
13
+ end
14
+ end
15
+ end
16
+
17
+
18
+ ###
19
+ ## Models
20
+ ###
21
+ class User < Model
22
+ def profile
23
+ @profile ||= Profile.new(name: 'N1', description: 'D1')
24
+ end
25
+ end
26
+
27
+ class UserInfo < Model
28
+ def user
29
+ @user ||= User.new(name: 'N1', email: 'E1')
30
+ end
31
+ end
32
+
33
+ class Profile < Model
34
+ end
35
+
36
+ class Category < Model
37
+ def posts
38
+ @posts ||= [Post.new(title: 'T1', body: 'B1'),
39
+ Post.new(title: 'T2', body: 'B2')]
40
+ end
41
+ end
42
+
43
+ class Post < Model
44
+ def comments
45
+ @comments ||= [Comment.new(content: 'C1'),
46
+ Comment.new(content: 'C2')]
47
+ end
48
+ end
49
+
50
+ class SpecialPost < Post
51
+ def special_comment
52
+ @speical_comment ||= Comment.new(content: 'special')
53
+ end
54
+ end
55
+
56
+ class Comment < Model
57
+ end
58
+
59
+ class WebLog < Model
60
+ end
61
+
62
+ class Interview < Model
63
+ def attachment
64
+ @attachment ||= Image.new(url: 'U1')
65
+ end
66
+ end
67
+
68
+ class Mail < Model
69
+ def attachments
70
+ @attachments ||= [Image.new(url: 'U1'),
71
+ Video.new(html: 'H1')]
72
+ end
73
+ end
74
+
75
+ class Image < Model
76
+ end
77
+
78
+ class Video < Model
79
+ end
80
+
81
+ ###
82
+ ## Serializers
83
+ ###
84
+ class UserSerializer < ActiveModel::Serializer
85
+ attributes :name, :email
86
+
87
+ has_one :profile
88
+ end
89
+
90
+ class UserInfoSerializer < ActiveModel::Serializer
91
+ has_one :user, serializer: UserSerializer
92
+ end
93
+
94
+ class ProfileSerializer < ActiveModel::Serializer
95
+ def description
96
+ description = object.read_attribute_for_serialization(:description)
97
+ scope ? "#{description} - #{scope}" : description
98
+ end
99
+
100
+ attributes :name, :description
101
+ end
102
+
103
+ class CategorySerializer < ActiveModel::Serializer
104
+ attributes :name
105
+
106
+ has_many :posts
107
+ end
108
+
109
+ class PostSerializer < ActiveModel::Serializer
110
+ attributes :title, :body
111
+
112
+ def title
113
+ keyword = serialization_options[:highlight_keyword]
114
+ title = object.read_attribute_for_serialization(:title)
115
+ title = title.gsub(keyword,"'#{keyword}'") if keyword
116
+ title
117
+ end
118
+
119
+ has_many :comments
120
+ end
121
+
122
+ class SpecialPostSerializer < ActiveModel::Serializer
123
+ attributes :title, :body
124
+ has_many :comments, root: :comments, embed_in_root: true, embed: :ids
125
+ has_one :special_comment, root: :comments, embed_in_root: true, embed: :ids
126
+ end
127
+
128
+ class CommentSerializer < ActiveModel::Serializer
129
+ attributes :content
130
+ end
131
+
132
+ class WebLogSerializer < ActiveModel::Serializer
133
+ attributes :name, :display_name
134
+ end
135
+
136
+ class WebLogLowerCamelSerializer < WebLogSerializer
137
+ format_keys :lower_camel
138
+ end
139
+
140
+ class InterviewSerializer < ActiveModel::Serializer
141
+ attributes :text
142
+
143
+ has_one :attachment, polymorphic: true
144
+ end
145
+
146
+ class MailSerializer < ActiveModel::Serializer
147
+ attributes :body
148
+
149
+ has_many :attachments, polymorphic: true
150
+ end
151
+
152
+ class ImageSerializer < ActiveModel::Serializer
153
+ attributes :url
154
+ end
155
+
156
+ class VideoSerializer < ActiveModel::Serializer
157
+ attributes :html
158
+ end
159
+
160
+ class ShortProfileSerializer < ::ProfileSerializer; end
161
+
162
+ module TestNamespace
163
+ class ProfileSerializer < ::ProfileSerializer; end
164
+ class UserSerializer < ::UserSerializer; end
165
+ end
166
+
167
+ ActiveModel::Serializer.setup do |config|
168
+ config.default_key_type = :name
169
+ end
170
+
171
+ class NameKeyUserSerializer < ActiveModel::Serializer
172
+ attributes :name, :email
173
+
174
+ has_one :profile
175
+ end
176
+
177
+ class NameKeyPostSerializer < ActiveModel::Serializer
178
+ attributes :title, :body
179
+
180
+ has_many :comments
181
+ end
182
+
183
+ ActiveModel::Serializer.setup do |config|
184
+ config.default_key_type = nil
185
+ end
186
+
187
+
@@ -0,0 +1 @@
1
+ <p>Hello.</p>
@@ -0,0 +1,105 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class NamespacedSerializationTest < ActionController::TestCase
6
+ class TestNamespace::MyController < ActionController::Base
7
+ def render_profile_with_namespace
8
+ render json: Profile.new({ name: 'Name 1', description: 'Description 1'})
9
+ end
10
+
11
+ def render_profiles_with_namespace
12
+ render json: [Profile.new({ name: 'Name 1', description: 'Description 1'})]
13
+ end
14
+
15
+ def render_comment
16
+ render json: Comment.new(content: 'Comment 1')
17
+ end
18
+
19
+ def render_comments
20
+ render json: [Comment.new(content: 'Comment 1')]
21
+ end
22
+
23
+ def render_hash
24
+ render json: {message: 'not found'}, status: 404
25
+ end
26
+ end
27
+
28
+ tests TestNamespace::MyController
29
+
30
+ def test_render_profile_with_namespace
31
+ get :render_profile_with_namespace
32
+ assert_serializer TestNamespace::ProfileSerializer
33
+ end
34
+
35
+ def test_render_profiles_with_namespace
36
+ get :render_profiles_with_namespace
37
+ assert_serializer TestNamespace::ProfileSerializer
38
+ end
39
+
40
+ def test_fallback_to_a_version_without_namespace
41
+ get :render_comment
42
+ assert_serializer CommentSerializer
43
+ end
44
+
45
+ def test_array_fallback_to_a_version_without_namespace
46
+ get :render_comments
47
+ assert_serializer CommentSerializer
48
+ end
49
+
50
+ def test_render_hash_regression
51
+ get :render_hash
52
+ assert_equal JSON.parse(response.body), {'message' => 'not found'}
53
+ end
54
+ end
55
+
56
+ class OptionNamespacedSerializationTest < ActionController::TestCase
57
+ class MyController < ActionController::Base
58
+ def default_serializer_options
59
+ {
60
+ namespace: TestNamespace
61
+ }
62
+ end
63
+
64
+ def render_profile_with_namespace_option
65
+ render json: Profile.new({ name: 'Name 1', description: 'Description 1'})
66
+ end
67
+
68
+ def render_profiles_with_namespace_option
69
+ render json: [Profile.new({ name: 'Name 1', description: 'Description 1'})]
70
+ end
71
+
72
+ def render_comment
73
+ render json: Comment.new(content: 'Comment 1')
74
+ end
75
+
76
+ def render_comments
77
+ render json: [Comment.new(content: 'Comment 1')]
78
+ end
79
+ end
80
+
81
+ tests MyController
82
+
83
+ def test_render_profile_with_namespace_option
84
+ get :render_profile_with_namespace_option
85
+ assert_serializer TestNamespace::ProfileSerializer
86
+ end
87
+
88
+ def test_render_profiles_with_namespace_option
89
+ get :render_profiles_with_namespace_option
90
+ assert_serializer TestNamespace::ProfileSerializer
91
+ end
92
+
93
+ def test_fallback_to_a_version_without_namespace
94
+ get :render_comment
95
+ assert_serializer CommentSerializer
96
+ end
97
+
98
+ def test_array_fallback_to_a_version_without_namespace
99
+ get :render_comments
100
+ assert_serializer CommentSerializer
101
+ end
102
+ end
103
+
104
+ end
105
+ end