active_model_serializers 0.8.4 → 0.9.0.alpha1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -45
- data/CONTRIBUTING.md +20 -0
- data/DESIGN.textile +4 -4
- data/{MIT-LICENSE.txt → MIT-LICENSE} +0 -0
- data/README.md +187 -113
- data/lib/action_controller/serialization.rb +30 -16
- data/lib/active_model/array_serializer.rb +36 -82
- data/lib/active_model/default_serializer.rb +22 -0
- data/lib/active_model/serializable.rb +25 -0
- data/lib/active_model/serializer.rb +126 -447
- data/lib/active_model/serializer/associations.rb +53 -211
- data/lib/active_model/serializer/config.rb +31 -0
- data/lib/active_model/serializer/generators/resource_override.rb +13 -0
- data/lib/{generators → active_model/serializer/generators}/serializer/USAGE +0 -0
- data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +14 -0
- data/lib/active_model/serializer/generators/serializer/serializer_generator.rb +37 -0
- data/lib/active_model/serializer/generators/serializer/templates/controller.rb +93 -0
- data/lib/active_model/serializer/generators/serializer/templates/serializer.rb +8 -0
- data/lib/active_model/serializer/railtie.rb +10 -0
- data/lib/active_model/{serializers → serializer}/version.rb +1 -1
- data/lib/active_model/serializer_support.rb +5 -0
- data/lib/active_model_serializers.rb +7 -86
- data/test/coverage_setup.rb +15 -0
- data/test/fixtures/active_record.rb +92 -0
- data/test/fixtures/poro.rb +64 -0
- data/test/integration/action_controller/serialization_test.rb +234 -0
- data/test/integration/active_record/active_record_test.rb +77 -0
- data/test/integration/generators/resource_generator_test.rb +26 -0
- data/test/integration/generators/scaffold_controller_generator_test.rb +67 -0
- data/test/integration/generators/serializer_generator_test.rb +41 -0
- data/test/test_app.rb +11 -0
- data/test/test_helper.rb +7 -41
- data/test/tmp/app/serializers/account_serializer.rb +3 -0
- data/test/unit/active_model/array_serializer/meta_test.rb +53 -0
- data/test/unit/active_model/array_serializer/root_test.rb +102 -0
- data/test/unit/active_model/array_serializer/scope_test.rb +24 -0
- data/test/unit/active_model/array_serializer/serialization_test.rb +83 -0
- data/test/unit/active_model/default_serializer_test.rb +13 -0
- data/test/unit/active_model/serializer/associations/build_serializer_test.rb +21 -0
- data/test/unit/active_model/serializer/associations_test.rb +19 -0
- data/test/unit/active_model/serializer/attributes_test.rb +41 -0
- data/test/unit/active_model/serializer/config_test.rb +86 -0
- data/test/unit/active_model/serializer/filter_test.rb +49 -0
- data/test/unit/active_model/serializer/has_many_test.rb +173 -0
- data/test/unit/active_model/serializer/has_one_test.rb +151 -0
- data/test/unit/active_model/serializer/meta_test.rb +39 -0
- data/test/unit/active_model/serializer/root_test.rb +117 -0
- data/test/unit/active_model/serializer/scope_test.rb +49 -0
- metadata +78 -74
- data/.gitignore +0 -18
- data/.travis.yml +0 -34
- data/Gemfile +0 -38
- data/Rakefile +0 -22
- data/active_model_serializers.gemspec +0 -24
- data/appveyor.yml +0 -27
- data/bench/perf.rb +0 -43
- data/cruft.md +0 -19
- data/lib/active_record/serializer_override.rb +0 -16
- data/lib/generators/resource_override.rb +0 -13
- data/lib/generators/serializer/serializer_generator.rb +0 -42
- data/lib/generators/serializer/templates/serializer.rb +0 -19
- data/test/array_serializer_test.rb +0 -75
- data/test/association_test.rb +0 -592
- data/test/caching_test.rb +0 -177
- data/test/generators_test.rb +0 -85
- data/test/no_serialization_scope_test.rb +0 -34
- data/test/serialization_scope_name_test.rb +0 -67
- data/test/serialization_test.rb +0 -396
- data/test/serializer_support_test.rb +0 -51
- data/test/serializer_test.rb +0 -1466
- data/test/test_fakes.rb +0 -218
@@ -1,231 +1,73 @@
|
|
1
|
+
require 'active_model/default_serializer'
|
2
|
+
require 'active_model/serializer'
|
3
|
+
|
1
4
|
module ActiveModel
|
2
5
|
class Serializer
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# cache the root so we can reuse it without falling back on a per-instance basis
|
22
|
-
begin
|
23
|
-
self.options[:root] ||= self.new(name, nil).root
|
24
|
-
rescue
|
25
|
-
# this could fail if it needs a valid source, for example a polymorphic association
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
self.options = {}
|
32
|
-
|
33
|
-
def initialize(name, source, options={})
|
34
|
-
@name = name
|
35
|
-
@source = source
|
36
|
-
@options = options
|
37
|
-
end
|
38
|
-
|
39
|
-
def option(key, default=nil)
|
40
|
-
if @options.key?(key)
|
41
|
-
@options[key]
|
42
|
-
elsif self.class.options.key?(key)
|
43
|
-
self.class.options[key]
|
44
|
-
else
|
45
|
-
default
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def target_serializer
|
50
|
-
serializer = option(:serializer)
|
51
|
-
serializer.is_a?(String) ? serializer.constantize : serializer
|
52
|
-
end
|
53
|
-
|
54
|
-
def source_serializer
|
55
|
-
@source
|
56
|
-
end
|
57
|
-
|
58
|
-
def key
|
59
|
-
option(:key) || @name
|
60
|
-
end
|
61
|
-
|
62
|
-
def root
|
63
|
-
option(:root) || @name
|
64
|
-
end
|
65
|
-
|
66
|
-
def name
|
67
|
-
option(:name) || @name
|
68
|
-
end
|
69
|
-
|
70
|
-
def associated_object
|
71
|
-
option(:value) || source_serializer.send(name)
|
72
|
-
end
|
73
|
-
|
74
|
-
def embed_ids?
|
75
|
-
[:id, :ids].include? option(:embed, source_serializer._embed)
|
76
|
-
end
|
77
|
-
|
78
|
-
def embed_objects?
|
79
|
-
[:object, :objects].include? option(:embed, source_serializer._embed)
|
80
|
-
end
|
81
|
-
|
82
|
-
def embed_in_root?
|
83
|
-
option(:include, source_serializer._root_embed)
|
84
|
-
end
|
85
|
-
|
86
|
-
def embeddable?
|
87
|
-
!associated_object.nil?
|
88
|
-
end
|
89
|
-
|
90
|
-
protected
|
91
|
-
|
92
|
-
def find_serializable(object)
|
93
|
-
if target_serializer
|
94
|
-
target_serializer.new(object, source_serializer.options)
|
95
|
-
elsif object.respond_to?(:active_model_serializer) && (ams = object.active_model_serializer)
|
96
|
-
ams.new(object, source_serializer.options)
|
97
|
-
else
|
98
|
-
object
|
99
|
-
end
|
100
|
-
end
|
6
|
+
class Association
|
7
|
+
def initialize(name, options={})
|
8
|
+
if options.has_key?(:include)
|
9
|
+
ActiveSupport::Deprecation.warn <<-WARN
|
10
|
+
** Notice: include was renamed to embed_in_root. **
|
11
|
+
WARN
|
12
|
+
end
|
13
|
+
|
14
|
+
@name = name.to_s
|
15
|
+
@options = options
|
16
|
+
self.embed = options.fetch(:embed) { CONFIG.embed }
|
17
|
+
@embed_in_root = options.fetch(:embed_in_root) { options.fetch(:include) { CONFIG.embed_in_root } }
|
18
|
+
@embed_key = options[:embed_key] || :id
|
19
|
+
@key = options[:key]
|
20
|
+
@embedded_key = options[:root] || name
|
21
|
+
|
22
|
+
serializer = @options[:serializer]
|
23
|
+
@serializer_class = serializer.is_a?(String) ? serializer.constantize : serializer
|
101
24
|
end
|
102
25
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
"#{@name.to_s.singularize}_ids".to_sym
|
109
|
-
else
|
110
|
-
@name
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def embed_key
|
115
|
-
if key = option(:embed_key)
|
116
|
-
key
|
117
|
-
else
|
118
|
-
:id
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def serialize
|
123
|
-
associated_object.map do |item|
|
124
|
-
find_serializable(item).serializable_hash
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def serializables
|
129
|
-
associated_object.map do |item|
|
130
|
-
find_serializable(item)
|
131
|
-
end
|
132
|
-
end
|
26
|
+
attr_reader :name, :embed_ids, :embed_objects
|
27
|
+
attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_class, :options
|
28
|
+
alias embed_ids? embed_ids
|
29
|
+
alias embed_objects? embed_objects
|
30
|
+
alias embed_in_root? embed_in_root
|
133
31
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
source_serializer.object.read_attribute_for_serialization(ids_key)
|
138
|
-
else
|
139
|
-
associated_object.map do |item|
|
140
|
-
item.read_attribute_for_serialization(embed_key)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
32
|
+
def embed=(embed)
|
33
|
+
@embed_ids = embed == :id || embed == :ids
|
34
|
+
@embed_objects = embed == :object || embed == :objects
|
144
35
|
end
|
145
36
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
false
|
150
|
-
else
|
151
|
-
true
|
152
|
-
end
|
153
|
-
end
|
37
|
+
def build_serializer(object, options = {})
|
38
|
+
@serializer_class.new(object, options.merge(@options))
|
39
|
+
end
|
154
40
|
|
155
|
-
|
156
|
-
|
41
|
+
class HasOne < Association
|
42
|
+
def initialize(name, *args)
|
43
|
+
super
|
44
|
+
@root_key = @embedded_key.to_s.pluralize
|
45
|
+
@key ||= "#{name}_id"
|
157
46
|
end
|
158
47
|
|
159
|
-
def
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
associated_object.class.to_s.pluralize.demodulize.underscore.to_sym
|
164
|
-
else
|
165
|
-
@name.to_s.pluralize.to_sym
|
166
|
-
end
|
48
|
+
def build_serializer(object, options = {})
|
49
|
+
@serializer_class ||= Serializer.serializer_for(object) || DefaultSerializer
|
50
|
+
options[:_wrap_in_array] = embed_in_root?
|
51
|
+
super
|
167
52
|
end
|
53
|
+
end
|
168
54
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
else
|
175
|
-
@name
|
176
|
-
end
|
55
|
+
class HasMany < Association
|
56
|
+
def initialize(name, *args)
|
57
|
+
super
|
58
|
+
@root_key = @embedded_key
|
59
|
+
@key ||= "#{name.to_s.singularize}_ids"
|
177
60
|
end
|
178
61
|
|
179
|
-
def
|
180
|
-
if
|
181
|
-
|
62
|
+
def build_serializer(object, options = {})
|
63
|
+
if @serializer_class && !(@serializer_class <= ArraySerializer)
|
64
|
+
@options[:each_serializer] = @serializer_class
|
65
|
+
@serializer_class = ArraySerializer
|
182
66
|
else
|
183
|
-
|
67
|
+
@serializer_class ||= ArraySerializer
|
184
68
|
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def polymorphic_key
|
188
|
-
associated_object.class.to_s.demodulize.underscore.to_sym
|
189
|
-
end
|
190
69
|
|
191
|
-
|
192
|
-
object = associated_object
|
193
|
-
|
194
|
-
if object && polymorphic?
|
195
|
-
{
|
196
|
-
:type => polymorphic_key,
|
197
|
-
polymorphic_key => find_serializable(object).serializable_hash
|
198
|
-
}
|
199
|
-
elsif object
|
200
|
-
find_serializable(object).serializable_hash
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
def serializables
|
205
|
-
object = associated_object
|
206
|
-
value = object && find_serializable(object)
|
207
|
-
value ? [value] : []
|
208
|
-
end
|
209
|
-
|
210
|
-
def serialize_ids
|
211
|
-
id_key = "#{@name}_id".to_sym
|
212
|
-
|
213
|
-
if polymorphic?
|
214
|
-
if associated_object
|
215
|
-
{
|
216
|
-
:type => polymorphic_key,
|
217
|
-
:id => associated_object.read_attribute_for_serialization(embed_key)
|
218
|
-
}
|
219
|
-
else
|
220
|
-
nil
|
221
|
-
end
|
222
|
-
elsif !option(:embed_key) && !source_serializer.respond_to?(@name.to_s) && source_serializer.object.respond_to?(id_key)
|
223
|
-
source_serializer.object.read_attribute_for_serialization(id_key)
|
224
|
-
elsif associated_object
|
225
|
-
associated_object.read_attribute_for_serialization(embed_key)
|
226
|
-
else
|
227
|
-
nil
|
228
|
-
end
|
70
|
+
super
|
229
71
|
end
|
230
72
|
end
|
231
73
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
class Serializer
|
3
|
+
class Config
|
4
|
+
def initialize(data = {})
|
5
|
+
@data = data
|
6
|
+
end
|
7
|
+
|
8
|
+
def each(&block)
|
9
|
+
@data.each(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear
|
13
|
+
@data.clear
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(name, *args)
|
17
|
+
name = name.to_s
|
18
|
+
return @data[name] if @data.include?(name)
|
19
|
+
match = name.match(/\A(.*?)([?=]?)\Z/)
|
20
|
+
case match[2]
|
21
|
+
when "="
|
22
|
+
@data[match[1]] = args.first
|
23
|
+
when "?"
|
24
|
+
!!@data[match[1]]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
CONFIG = Config.new('embed' => :objects) # :nodoc:
|
30
|
+
end
|
31
|
+
end
|
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
|
3
|
+
|
4
|
+
module Rails
|
5
|
+
module Generators
|
6
|
+
class ScaffoldControllerGenerator
|
7
|
+
if Rails::VERSION::MAJOR >= 4
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
9
|
+
|
10
|
+
hook_for :serializer, default: true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Rails
|
2
|
+
module Generators
|
3
|
+
class SerializerGenerator < NamedBase
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
check_class_collision suffix: 'Serializer'
|
6
|
+
|
7
|
+
argument :attributes, type: :array, default: [], banner: 'field:type field:type'
|
8
|
+
|
9
|
+
class_option :parent, type: :string, desc: 'The parent class for the generated serializer'
|
10
|
+
|
11
|
+
def create_serializer_file
|
12
|
+
template 'serializer.rb', File.join('app/serializers', class_path, "#{file_name}_serializer.rb")
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def attributes_names
|
18
|
+
[:id] + attributes.select { |attr| !attr.reference? }.map { |a| a.name.to_sym }
|
19
|
+
end
|
20
|
+
|
21
|
+
def association_names
|
22
|
+
attributes.select { |attr| attr.reference? }.map { |a| a.name.to_sym }
|
23
|
+
end
|
24
|
+
|
25
|
+
def parent_class_name
|
26
|
+
if options[:parent]
|
27
|
+
options[:parent]
|
28
|
+
elsif (ns = Rails::Generators.namespace) && ns.const_defined?(:ApplicationSerializer) ||
|
29
|
+
defined?(::ApplicationSerializer)
|
30
|
+
'ApplicationSerializer'
|
31
|
+
else
|
32
|
+
'ActiveModel::Serializer'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
<% if namespaced? -%>
|
2
|
+
require_dependency "<%= namespaced_file_path %>/application_controller"
|
3
|
+
|
4
|
+
<% end -%>
|
5
|
+
<% module_namespacing do -%>
|
6
|
+
class <%= controller_class_name %>Controller < ApplicationController
|
7
|
+
before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy]
|
8
|
+
|
9
|
+
# GET <%= route_url %>
|
10
|
+
# GET <%= route_url %>.json
|
11
|
+
def index
|
12
|
+
@<%= plural_table_name %> = <%= orm_class.all(class_name) %>
|
13
|
+
|
14
|
+
respond_to do |format|
|
15
|
+
format.html # index.html.erb
|
16
|
+
format.json { render json: <%= "@#{plural_table_name}" %> }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# GET <%= route_url %>/1
|
21
|
+
# GET <%= route_url %>/1.json
|
22
|
+
def show
|
23
|
+
respond_to do |format|
|
24
|
+
format.html # show.html.erb
|
25
|
+
format.json { render json: <%= "@#{singular_table_name}" %> }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# GET <%= route_url %>/new
|
30
|
+
def new
|
31
|
+
@<%= singular_table_name %> = <%= orm_class.build(class_name) %>
|
32
|
+
end
|
33
|
+
|
34
|
+
# GET <%= route_url %>/1/edit
|
35
|
+
def edit
|
36
|
+
end
|
37
|
+
|
38
|
+
# POST <%= route_url %>
|
39
|
+
# POST <%= route_url %>.json
|
40
|
+
def create
|
41
|
+
@<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
|
42
|
+
|
43
|
+
respond_to do |format|
|
44
|
+
if @<%= orm_instance.save %>
|
45
|
+
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> }
|
46
|
+
format.json { render json: <%= "@#{singular_table_name}" %>, status: :created }
|
47
|
+
else
|
48
|
+
format.html { render action: 'new' }
|
49
|
+
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# PATCH/PUT <%= route_url %>/1
|
55
|
+
# PATCH/PUT <%= route_url %>/1.json
|
56
|
+
def update
|
57
|
+
respond_to do |format|
|
58
|
+
if @<%= orm_instance.update("#{singular_table_name}_params") %>
|
59
|
+
format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> }
|
60
|
+
format.json { head :no_content }
|
61
|
+
else
|
62
|
+
format.html { render action: 'edit' }
|
63
|
+
format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# DELETE <%= route_url %>/1
|
69
|
+
# DELETE <%= route_url %>/1.json
|
70
|
+
def destroy
|
71
|
+
@<%= orm_instance.destroy %>
|
72
|
+
respond_to do |format|
|
73
|
+
format.html { redirect_to <%= index_helper %>_url }
|
74
|
+
format.json { head :no_content }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
# Use callbacks to share common setup or constraints between actions.
|
80
|
+
def set_<%= singular_table_name %>
|
81
|
+
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
82
|
+
end
|
83
|
+
|
84
|
+
# Never trust parameters from the scary internet, only allow the white list through.
|
85
|
+
def <%= "#{singular_table_name}_params" %>
|
86
|
+
<%- if attributes_names.empty? -%>
|
87
|
+
params[<%= ":#{singular_table_name}" %>]
|
88
|
+
<%- else -%>
|
89
|
+
params.require(<%= ":#{singular_table_name}" %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
|
90
|
+
<%- end -%>
|
91
|
+
end
|
92
|
+
end
|
93
|
+
<% end -%>
|