simple_json_api 0.0.4 → 0.0.5
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/.travis.yml +1 -1
- data/README.md +6 -0
- data/lib/simple_json_api/api_node.rb +26 -13
- data/lib/simple_json_api/builder.rb +6 -3
- data/lib/simple_json_api/dsl.rb +7 -6
- data/lib/simple_json_api/json_api_wrapper.rb +4 -2
- data/lib/simple_json_api/member/links.rb +5 -0
- data/lib/simple_json_api/refinements/active_record.rb +1 -1
- data/lib/simple_json_api/refinements/array.rb +1 -1
- data/lib/simple_json_api/resource_serializer.rb +27 -8
- data/lib/simple_json_api/serializer.rb +7 -5
- data/lib/simple_json_api/version.rb +1 -1
- data/lib/simple_json_api.rb +2 -2
- data/test/integration/render_basic_test.rb +27 -9
- data/test/integration/render_fields_test.rb +34 -11
- data/test/integration/render_include_test.rb +75 -27
- data/test/integration/render_nested_include_test.rb +40 -12
- data/test/integration/render_pagination_test.rb +101 -0
- data/test/setup/data.rb +0 -1
- metadata +5 -9
- data/lib/generators/simple_json_api/resource/USAGE +0 -8
- data/lib/generators/simple_json_api/resource/resource_generator.rb +0 -73
- data/lib/generators/simple_json_api/resource/templates/controller_template.rb.erb +0 -34
- data/lib/generators/simple_json_api/resource/templates/serializer_template.rb.erb +0 -14
- data/test/generators/simple_json_api/resource_generator_test.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75b1e1d7eab7671430dab2b735ea9b3ce3d0b921
|
4
|
+
data.tar.gz: 04ad4e30da53078764dbafa68edab1ca81f579b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8eabae974ab4bf5aa7775b59bd2af0ae6a27ca46e72aaf8be3831ad586d040b6f28a2b400e51c78efff351b1168602cf7d4f841c01b202596833f3f840197ea
|
7
|
+
data.tar.gz: 43ff3b97dc119fcf716b5a4890785321bfe7077cbfdbc7e79a9d4d1449fb5b100b6d2defde06de30ab05d1be079b8f71ec74d8328d6c1255d5864da7fadaa159
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -20,6 +20,11 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
$ gem install simple_json_api
|
22
22
|
|
23
|
+
|
24
|
+
### Rails Integration
|
25
|
+
|
26
|
+
Use the gem [simple_json_api-rails](https://github.com/dajacques/simple_json_api-rails)
|
27
|
+
|
23
28
|
## Usage
|
24
29
|
|
25
30
|
### Define serializers
|
@@ -59,6 +64,7 @@ render json: SimpleJsonApi.render(
|
|
59
64
|
When rendering the model is the AR data to be serialized, if it is an Array the ArraySerializer will be used for the top collection.
|
60
65
|
`fields` and `include` follow the jsonapi spec. [Include](http://jsonapi.org/format/#fetching-includes) will be the associations to be included in the generated json. [Fields](http://jsonapi.org/format/#fetching-sparse-fieldsets) is the list of attributes that will be included. The primary key will always be included.
|
61
66
|
|
67
|
+
|
62
68
|
## TODO
|
63
69
|
|
64
70
|
0. Better documentation
|
@@ -20,6 +20,10 @@ module SimpleJsonApi
|
|
20
20
|
@associations = [] # list of api_nodes
|
21
21
|
end
|
22
22
|
|
23
|
+
def collection?
|
24
|
+
@serializer.is_a? ArraySerializer
|
25
|
+
end
|
26
|
+
|
23
27
|
def load
|
24
28
|
return self unless serializer_actual._associations
|
25
29
|
serializer_actual._associations.each do |association|
|
@@ -29,27 +33,35 @@ module SimpleJsonApi
|
|
29
33
|
end
|
30
34
|
|
31
35
|
def serializer_actual
|
32
|
-
@serializer_actual ||= @each_serializer ||
|
36
|
+
@serializer_actual ||= @each_serializer || serializer
|
33
37
|
end
|
34
38
|
|
35
39
|
def add_association(association)
|
36
40
|
return unless @assoc_list.key? association.plural_name
|
37
41
|
resource = serializer.associated_object(association.name)
|
38
42
|
Array(resource).each do |object|
|
39
|
-
|
40
|
-
serializer = SerializerFactory.create(
|
41
|
-
object, each_serializer, self.serializer._builder
|
42
|
-
)
|
43
|
-
self <<
|
44
|
-
ApiNode.new(
|
45
|
-
association.plural_name,
|
46
|
-
serializer,
|
47
|
-
@assoc_list[association.plural_name],
|
48
|
-
serializer._each_serializer
|
49
|
-
).load
|
43
|
+
add_nodes(association, object)
|
50
44
|
end
|
51
45
|
end
|
52
46
|
|
47
|
+
def add_nodes(association, object)
|
48
|
+
each_serializer = Serializer.for(object, association)
|
49
|
+
serializer = SerializerFactory.create(
|
50
|
+
object, each_serializer, self.serializer._builder
|
51
|
+
)
|
52
|
+
add_node(association, serializer)
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_node(association, serializer)
|
56
|
+
self <<
|
57
|
+
ApiNode.new(
|
58
|
+
association.plural_name,
|
59
|
+
serializer,
|
60
|
+
@assoc_list[association.plural_name],
|
61
|
+
serializer._each_serializer
|
62
|
+
).load
|
63
|
+
end
|
64
|
+
|
53
65
|
def <<(node)
|
54
66
|
add_assoc(node)
|
55
67
|
end
|
@@ -59,7 +71,8 @@ module SimpleJsonApi
|
|
59
71
|
end
|
60
72
|
|
61
73
|
# def display(offset = '')
|
62
|
-
# ap "DISPLAY: #{offset}#{@name}, #{@assoc_list},
|
74
|
+
# ap "DISPLAY: #{offset}#{@name}, #{@assoc_list}, \
|
75
|
+
# #{Array(@object).first.class}, #{Array(@object).map(&:id)}"
|
63
76
|
# @associations.each do |assoc|
|
64
77
|
# assoc.display(offset + ' ')
|
65
78
|
# end
|
@@ -19,17 +19,20 @@ module SimpleJsonApi
|
|
19
19
|
def_delegators :@field_list, :fields_for
|
20
20
|
|
21
21
|
# TODO: sort: nil
|
22
|
-
def initialize(object, wrapper, serializer, fields, include)
|
22
|
+
def initialize(object, wrapper, serializer, fields, include, page)
|
23
23
|
@object = object
|
24
24
|
@wrapper = wrapper
|
25
25
|
@field_list = FieldList.new(fields, serializer)
|
26
26
|
@include = IncludeList.new(include).parse
|
27
|
+
@page = page
|
27
28
|
@serializer = SerializerFactory.create(object, serializer, self)
|
28
29
|
end
|
29
30
|
|
30
31
|
def as_json(options = nil)
|
31
|
-
root_node = ApiNode.new(
|
32
|
-
|
32
|
+
root_node = ApiNode.new(
|
33
|
+
serializer._root_name, serializer, include.include_hash
|
34
|
+
).load
|
35
|
+
wrapper.new(root_node, @page).as_json(options)
|
33
36
|
end
|
34
37
|
end
|
35
38
|
end
|
data/lib/simple_json_api/dsl.rb
CHANGED
@@ -69,14 +69,15 @@ module SimpleJsonApi
|
|
69
69
|
define_assoc_method(association) # unless defined? association.name
|
70
70
|
end
|
71
71
|
|
72
|
-
def define_assoc_method(
|
73
|
-
if
|
74
|
-
define_method
|
75
|
-
_object.send(
|
72
|
+
def define_assoc_method(assoc)
|
73
|
+
if assoc.type == :has_many
|
74
|
+
define_method assoc.name do |includes = nil|
|
75
|
+
_object.send(assoc.name).includes(includes).to_a \
|
76
|
+
if _object.respond_to?(assoc.name)
|
76
77
|
end
|
77
78
|
else
|
78
|
-
define_method
|
79
|
-
_object.send(
|
79
|
+
define_method assoc.name do |_includes = nil|
|
80
|
+
_object.send(assoc.name) if _object.respond_to?(assoc.name)
|
80
81
|
end
|
81
82
|
end
|
82
83
|
end
|
@@ -6,8 +6,9 @@ require 'simple_json_api/member/meta'
|
|
6
6
|
module SimpleJsonApi
|
7
7
|
# JSONAPI Wrapper
|
8
8
|
class JsonApiWrapper
|
9
|
-
def initialize(root_node)
|
9
|
+
def initialize(root_node, page)
|
10
10
|
@root_node = root_node
|
11
|
+
@page = page
|
11
12
|
@result = {}
|
12
13
|
end
|
13
14
|
|
@@ -27,7 +28,8 @@ module SimpleJsonApi
|
|
27
28
|
end
|
28
29
|
|
29
30
|
def links
|
30
|
-
@
|
31
|
+
page = @root_node.collection? ? @page : {}
|
32
|
+
@result[:links] ||= Member::Links.new(page).content
|
31
33
|
end
|
32
34
|
|
33
35
|
def meta
|
@@ -40,10 +40,10 @@ module SimpleJsonApi
|
|
40
40
|
_fields.each do |attribute, _attr_opts|
|
41
41
|
hash[attribute] = send(attribute).to_s
|
42
42
|
end
|
43
|
-
hash[:href] = href if self.class.method_defined? :href
|
44
43
|
end
|
45
44
|
|
46
45
|
def link_values(root)
|
46
|
+
root[:self] = href if self.class.method_defined? :href
|
47
47
|
self.class._associations.each do |association|
|
48
48
|
root[association.key] = link(association)
|
49
49
|
end
|
@@ -51,14 +51,33 @@ module SimpleJsonApi
|
|
51
51
|
|
52
52
|
def link(association)
|
53
53
|
if association.type == :has_many
|
54
|
-
|
55
|
-
resource = send(association.name, includes)
|
56
|
-
resource.map do |obj|
|
57
|
-
association[:polymorphic] ? obj.typed_json_id : obj.json_id
|
58
|
-
end
|
54
|
+
link_many(association)
|
59
55
|
else
|
60
|
-
|
61
|
-
|
56
|
+
link_one(association)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def link_many(association)
|
61
|
+
resource = send(association.name, includes(association))
|
62
|
+
{ linkage: linkage_values(resource) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def link_one(association)
|
66
|
+
resource = send(association.name)
|
67
|
+
{ linkage: resource.typed_json_id } if resource
|
68
|
+
end
|
69
|
+
|
70
|
+
def linkage_values(resource)
|
71
|
+
resource.map do |obj|
|
72
|
+
obj.typed_json_id
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def includes(association)
|
77
|
+
if association.polymorphic
|
78
|
+
[]
|
79
|
+
else
|
80
|
+
Serializer.includes(association)
|
62
81
|
end
|
63
82
|
end
|
64
83
|
|
@@ -40,10 +40,10 @@ module SimpleJsonApi
|
|
40
40
|
def builder_fields
|
41
41
|
bf = _builder.fields_for(_root_name).presence
|
42
42
|
fields = if bf.present?
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
(required_fields + Array(bf)).uniq
|
44
|
+
else
|
45
|
+
default_fields ? default_fields & all_fields : all_fields
|
46
|
+
end
|
47
47
|
(required_fields + Array(fields)).uniq.map(&:to_sym)
|
48
48
|
end
|
49
49
|
|
@@ -67,7 +67,9 @@ module SimpleJsonApi
|
|
67
67
|
|
68
68
|
def includes(association)
|
69
69
|
serializer = Serializer.for_regular(association)
|
70
|
-
serializer._associations.reject(&:polymorphic).map
|
70
|
+
serializer._associations.reject(&:polymorphic).map do |assoc|
|
71
|
+
assoc[:name]
|
72
|
+
end if serializer
|
71
73
|
end
|
72
74
|
|
73
75
|
def for_regular(association)
|
data/lib/simple_json_api.rb
CHANGED
@@ -10,7 +10,7 @@ require 'simple_json_api/helper'
|
|
10
10
|
# SimpleJsonApi
|
11
11
|
module SimpleJsonApi
|
12
12
|
# Main hook to generate json
|
13
|
-
def self.render(model:, serializer:, fields: nil, include: nil, wrapper: JsonApiWrapper)
|
14
|
-
Builder.new(model, wrapper, serializer, fields, include).to_json
|
13
|
+
def self.render(model:, serializer:, fields: nil, include: nil, page: {}, wrapper: JsonApiWrapper)
|
14
|
+
Builder.new(model, wrapper, serializer, fields, include, page).to_json
|
15
15
|
end
|
16
16
|
end
|
@@ -25,10 +25,16 @@ module SimpleJsonApi
|
|
25
25
|
'name' => 'First Project',
|
26
26
|
'description' => 'The first project',
|
27
27
|
'position' => '',
|
28
|
-
'href' => 'http://example.com/projects/100',
|
29
28
|
'links' => {
|
30
|
-
'
|
31
|
-
'
|
29
|
+
'self' => 'http://example.com/projects/100',
|
30
|
+
'todolist' => {
|
31
|
+
'linkage' => { 'type' => 'todolists', 'id' => '200' }
|
32
|
+
},
|
33
|
+
'tags' => {
|
34
|
+
'linkage' => [
|
35
|
+
{ 'type' => 'tags', 'id' => '10' }
|
36
|
+
]
|
37
|
+
}
|
32
38
|
}
|
33
39
|
}
|
34
40
|
}
|
@@ -49,10 +55,16 @@ module SimpleJsonApi
|
|
49
55
|
'name' => 'First Project',
|
50
56
|
'description' => 'The first project',
|
51
57
|
'position' => '',
|
52
|
-
'href' => 'http://example.com/projects/100',
|
53
58
|
'links' => {
|
54
|
-
'
|
55
|
-
'
|
59
|
+
'self' => 'http://example.com/projects/100',
|
60
|
+
'todolist' => {
|
61
|
+
'linkage' => { 'type' => 'todolists', 'id' => '200' }
|
62
|
+
},
|
63
|
+
'tags' => {
|
64
|
+
'linkage' => [
|
65
|
+
{ 'type' => 'tags', 'id' => '10' }
|
66
|
+
]
|
67
|
+
}
|
56
68
|
}
|
57
69
|
},
|
58
70
|
{
|
@@ -61,10 +73,16 @@ module SimpleJsonApi
|
|
61
73
|
'name' => 'Second Project',
|
62
74
|
'description' => 'The second project',
|
63
75
|
'position' => '',
|
64
|
-
'href' => 'http://example.com/projects/110',
|
65
76
|
'links' => {
|
66
|
-
'
|
67
|
-
'
|
77
|
+
'self' => 'http://example.com/projects/110',
|
78
|
+
'todolist' => {
|
79
|
+
'linkage' => { 'type' => 'todolists', 'id' => '210' }
|
80
|
+
},
|
81
|
+
'tags' => {
|
82
|
+
'linkage' => [
|
83
|
+
{ 'type' => 'tags', 'id' => '20' }
|
84
|
+
]
|
85
|
+
}
|
68
86
|
}
|
69
87
|
}
|
70
88
|
]
|
@@ -29,10 +29,16 @@ module SimpleJsonApi
|
|
29
29
|
'id' => '100',
|
30
30
|
'name' => 'First Project',
|
31
31
|
'description' => 'The first project',
|
32
|
-
'href' => 'http://example.com/projects/100',
|
33
32
|
'links' => {
|
34
|
-
'
|
35
|
-
'
|
33
|
+
'self' => 'http://example.com/projects/100',
|
34
|
+
'todolist' => {
|
35
|
+
'linkage' => { 'type' => 'todolists', 'id' => '200' }
|
36
|
+
},
|
37
|
+
'tags' => {
|
38
|
+
'linkage' => [
|
39
|
+
{ 'type' => 'tags', 'id' => '10' }
|
40
|
+
]
|
41
|
+
}
|
36
42
|
}
|
37
43
|
}
|
38
44
|
}
|
@@ -53,10 +59,16 @@ module SimpleJsonApi
|
|
53
59
|
'id' => '100',
|
54
60
|
'name' => 'First Project',
|
55
61
|
'description' => 'The first project',
|
56
|
-
'href' => 'http://example.com/projects/100',
|
57
62
|
'links' => {
|
58
|
-
'
|
59
|
-
'
|
63
|
+
'self' => 'http://example.com/projects/100',
|
64
|
+
'todolist' => {
|
65
|
+
'linkage' => { 'type' => 'todolists', 'id' => '200' }
|
66
|
+
},
|
67
|
+
'tags' => {
|
68
|
+
'linkage' => [
|
69
|
+
{ 'type' => 'tags', 'id' => '10' }
|
70
|
+
]
|
71
|
+
}
|
60
72
|
}
|
61
73
|
},
|
62
74
|
{
|
@@ -64,10 +76,16 @@ module SimpleJsonApi
|
|
64
76
|
'id' => '110',
|
65
77
|
'name' => 'Second Project',
|
66
78
|
'description' => 'The second project',
|
67
|
-
'href' => 'http://example.com/projects/110',
|
68
79
|
'links' => {
|
69
|
-
'
|
70
|
-
'
|
80
|
+
'self' => 'http://example.com/projects/110',
|
81
|
+
'todolist' => {
|
82
|
+
'linkage' => { 'type' => 'todolists', 'id' => '210' }
|
83
|
+
},
|
84
|
+
'tags' => {
|
85
|
+
'linkage' => [
|
86
|
+
{ 'type' => 'tags', 'id' => '20' }
|
87
|
+
]
|
88
|
+
}
|
71
89
|
}
|
72
90
|
}
|
73
91
|
]
|
@@ -86,9 +104,14 @@ module SimpleJsonApi
|
|
86
104
|
'type' => 'todos',
|
87
105
|
'id' => '300',
|
88
106
|
'action' => 'Milk',
|
89
|
-
'href' => 'http://example.com/todos/300',
|
90
107
|
'links' => {
|
91
|
-
'
|
108
|
+
'self' => 'http://example.com/todos/300',
|
109
|
+
'tags' => {
|
110
|
+
'linkage' => [
|
111
|
+
{ 'type' => 'tags', 'id' => '10' },
|
112
|
+
{ 'type' => 'tags', 'id' => '30' }
|
113
|
+
]
|
114
|
+
}
|
92
115
|
}
|
93
116
|
}
|
94
117
|
}
|
@@ -26,10 +26,16 @@ module SimpleJsonApi
|
|
26
26
|
'name' => 'First Project',
|
27
27
|
'description' => 'The first project',
|
28
28
|
'position' => '',
|
29
|
-
'href' => 'http://example.com/projects/100',
|
30
29
|
'links' => {
|
31
|
-
'
|
32
|
-
'
|
30
|
+
'self' => 'http://example.com/projects/100',
|
31
|
+
'todolist' => {
|
32
|
+
'linkage' => { 'type' => 'todolists', 'id' => '200' }
|
33
|
+
},
|
34
|
+
'tags' => {
|
35
|
+
'linkage' => [
|
36
|
+
{ 'type' => 'tags', 'id' => '10' }
|
37
|
+
]
|
38
|
+
}
|
33
39
|
}
|
34
40
|
},
|
35
41
|
'included' => [
|
@@ -37,10 +43,19 @@ module SimpleJsonApi
|
|
37
43
|
'type' => 'todolists',
|
38
44
|
'id' => '200',
|
39
45
|
'description' => 'Groceries',
|
40
|
-
'href' => 'http://example.com/todolists/200',
|
41
46
|
'links' => {
|
42
|
-
'
|
43
|
-
'
|
47
|
+
'self' => 'http://example.com/todolists/200',
|
48
|
+
'todos' => {
|
49
|
+
'linkage' => [
|
50
|
+
{ 'type' => 'todos', 'id' => '300' },
|
51
|
+
{ 'type' => 'todos', 'id' => '301' }
|
52
|
+
]
|
53
|
+
},
|
54
|
+
'tags' => {
|
55
|
+
'linkage' => [
|
56
|
+
{ 'type' => 'tags', 'id' => '30' }
|
57
|
+
]
|
58
|
+
}
|
44
59
|
}
|
45
60
|
}
|
46
61
|
]
|
@@ -63,10 +78,16 @@ module SimpleJsonApi
|
|
63
78
|
'name' => 'First Project',
|
64
79
|
'description' => 'The first project',
|
65
80
|
'position' => '',
|
66
|
-
'href' => 'http://example.com/projects/100',
|
67
81
|
'links' => {
|
68
|
-
'
|
69
|
-
'
|
82
|
+
'self' => 'http://example.com/projects/100',
|
83
|
+
'todolist' => {
|
84
|
+
'linkage' => { 'type' => 'todolists', 'id' => '200' }
|
85
|
+
},
|
86
|
+
'tags' => {
|
87
|
+
'linkage' => [
|
88
|
+
{ 'type' => 'tags', 'id' => '10' }
|
89
|
+
]
|
90
|
+
}
|
70
91
|
}
|
71
92
|
},
|
72
93
|
{
|
@@ -75,10 +96,16 @@ module SimpleJsonApi
|
|
75
96
|
'name' => 'Second Project',
|
76
97
|
'description' => 'The second project',
|
77
98
|
'position' => '',
|
78
|
-
'href' => 'http://example.com/projects/110',
|
79
99
|
'links' => {
|
80
|
-
'
|
81
|
-
'
|
100
|
+
'self' => 'http://example.com/projects/110',
|
101
|
+
'todolist' => {
|
102
|
+
'linkage' => { 'type' => 'todolists', 'id' => '210' }
|
103
|
+
},
|
104
|
+
'tags' => {
|
105
|
+
'linkage' => [
|
106
|
+
{ 'type' => 'tags', 'id' => '20' }
|
107
|
+
]
|
108
|
+
}
|
82
109
|
}
|
83
110
|
}
|
84
111
|
],
|
@@ -87,10 +114,19 @@ module SimpleJsonApi
|
|
87
114
|
'type' => 'todolists',
|
88
115
|
'id' => '200',
|
89
116
|
'description' => 'Groceries',
|
90
|
-
'href' => 'http://example.com/todolists/200',
|
91
117
|
'links' => {
|
92
|
-
'
|
93
|
-
'
|
118
|
+
'self' => 'http://example.com/todolists/200',
|
119
|
+
'todos' => {
|
120
|
+
'linkage' => [
|
121
|
+
{ 'type' => 'todos', 'id' => '300' },
|
122
|
+
{ 'type' => 'todos', 'id' => '301' }
|
123
|
+
]
|
124
|
+
},
|
125
|
+
'tags' => {
|
126
|
+
'linkage' => [
|
127
|
+
{ 'type' => 'tags', 'id' => '30' }
|
128
|
+
]
|
129
|
+
}
|
94
130
|
}
|
95
131
|
},
|
96
132
|
{
|
@@ -98,10 +134,18 @@ module SimpleJsonApi
|
|
98
134
|
'id' => '210',
|
99
135
|
'description' => 'Groceries',
|
100
136
|
'description' => 'Work',
|
101
|
-
'href' => 'http://example.com/todolists/210',
|
102
137
|
'links' => {
|
103
|
-
'
|
104
|
-
'
|
138
|
+
'self' => 'http://example.com/todolists/210',
|
139
|
+
'todos' => {
|
140
|
+
'linkage' => [
|
141
|
+
{ 'type' => 'todos', 'id' => '310' },
|
142
|
+
{ 'type' => 'todos', 'id' => '320' },
|
143
|
+
{ 'type' => 'todos', 'id' => '330' }
|
144
|
+
]
|
145
|
+
},
|
146
|
+
'tags' => {
|
147
|
+
'linkage' => []
|
148
|
+
}
|
105
149
|
}
|
106
150
|
},
|
107
151
|
{
|
@@ -110,12 +154,14 @@ module SimpleJsonApi
|
|
110
154
|
'guid' => '10',
|
111
155
|
'name' => 'Urgent!',
|
112
156
|
'links' => {
|
113
|
-
'taggables' =>
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
157
|
+
'taggables' => {
|
158
|
+
'linkage' => [
|
159
|
+
{ 'type' => 'projects', 'id' => '100' },
|
160
|
+
{ 'type' => 'todos', 'id' => '300' },
|
161
|
+
{ 'type' => 'todos', 'id' => '301' },
|
162
|
+
{ 'type' => 'todos', 'id' => '330' }
|
163
|
+
]
|
164
|
+
}
|
119
165
|
}
|
120
166
|
},
|
121
167
|
{
|
@@ -124,9 +170,11 @@ module SimpleJsonApi
|
|
124
170
|
'guid' => '20',
|
125
171
|
'name' => 'On Hold',
|
126
172
|
'links' => {
|
127
|
-
'taggables' =>
|
128
|
-
|
129
|
-
|
173
|
+
'taggables' => {
|
174
|
+
'linkage' => [
|
175
|
+
{ 'type' => 'projects', 'id' => '110' }
|
176
|
+
]
|
177
|
+
}
|
130
178
|
}
|
131
179
|
}
|
132
180
|
]
|
@@ -24,44 +24,72 @@ module SimpleJsonApi
|
|
24
24
|
'data' => {
|
25
25
|
'type' => 'projects',
|
26
26
|
'id' => '100',
|
27
|
-
'href' => 'http://example.com/projects/100',
|
28
27
|
'links' => {
|
29
|
-
'
|
30
|
-
'
|
28
|
+
'self' => 'http://example.com/projects/100',
|
29
|
+
'todolist' => {
|
30
|
+
'linkage' => { 'type' => 'todolists', 'id' => '200' }
|
31
|
+
},
|
32
|
+
'tags' => {
|
33
|
+
'linkage' => [
|
34
|
+
{ 'type' => 'tags', 'id' => '10' }
|
35
|
+
]
|
36
|
+
}
|
31
37
|
}
|
32
38
|
},
|
33
39
|
'included' => [
|
34
40
|
{
|
35
41
|
'type' => 'todolists',
|
36
42
|
'id' => '200',
|
37
|
-
'href' => 'http://example.com/todolists/200',
|
38
43
|
'links' => {
|
39
|
-
'
|
40
|
-
'
|
44
|
+
'self' => 'http://example.com/todolists/200',
|
45
|
+
'todos' => {
|
46
|
+
'linkage' => [
|
47
|
+
{ 'type' => 'todos', 'id' => '300' },
|
48
|
+
{ 'type' => 'todos', 'id' => '301' }
|
49
|
+
]
|
50
|
+
},
|
51
|
+
'tags' => {
|
52
|
+
'linkage' => [
|
53
|
+
{ 'type' => 'tags', 'id' => '30' }
|
54
|
+
]
|
55
|
+
}
|
41
56
|
}
|
42
57
|
},
|
43
58
|
{
|
44
59
|
'type' => 'todos',
|
45
60
|
'id' => '300',
|
46
|
-
'href' => 'http://example.com/todos/300',
|
47
61
|
'links' => {
|
48
|
-
'
|
62
|
+
'self' => 'http://example.com/todos/300',
|
63
|
+
'tags' => {
|
64
|
+
'linkage' => [
|
65
|
+
{ 'type' => 'tags', 'id' => '10' },
|
66
|
+
{ 'type' => 'tags', 'id' => '30' }
|
67
|
+
]
|
68
|
+
}
|
49
69
|
}
|
50
70
|
},
|
51
71
|
{
|
52
72
|
'type' => 'todos',
|
53
73
|
'id' => '301',
|
54
|
-
'href' => 'http://example.com/todos/301',
|
55
74
|
'links' => {
|
56
|
-
'
|
75
|
+
'self' => 'http://example.com/todos/301',
|
76
|
+
'tags' => {
|
77
|
+
'linkage' => [
|
78
|
+
{ 'type' => 'tags', 'id' => '10' }
|
79
|
+
]
|
80
|
+
}
|
57
81
|
}
|
58
82
|
},
|
59
83
|
{
|
60
84
|
'type' => 'todos',
|
61
85
|
'id' => '330',
|
62
|
-
'href' => 'http://example.com/todos/330',
|
63
86
|
'links' => {
|
64
|
-
'
|
87
|
+
'self' => 'http://example.com/todos/330',
|
88
|
+
'tags' => {
|
89
|
+
'linkage' => [
|
90
|
+
{ 'type' => 'tags', 'id' => '10' }
|
91
|
+
]
|
92
|
+
}
|
65
93
|
}
|
66
94
|
}
|
67
95
|
]
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# SimpleJsonApi
|
4
|
+
module SimpleJsonApi
|
5
|
+
describe 'RenderPaginationTest' do
|
6
|
+
it 'should match json hash for a project with no options' do
|
7
|
+
actual_project.must_match_json expected_project
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should match json hash for a project array with no options' do
|
11
|
+
actual_projects.must_match_json expected_projects
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:actual_project) do
|
15
|
+
SimpleJsonApi.render(
|
16
|
+
model: Project.first,
|
17
|
+
serializer: ProjectSerializer,
|
18
|
+
page: { number: 5, size: 20, total: 19 }
|
19
|
+
)
|
20
|
+
end
|
21
|
+
let(:expected_project) do
|
22
|
+
{
|
23
|
+
'data' => {
|
24
|
+
'type' => 'projects',
|
25
|
+
'id' => '100',
|
26
|
+
'name' => 'First Project',
|
27
|
+
'description' => 'The first project',
|
28
|
+
'position' => '',
|
29
|
+
'links' => {
|
30
|
+
'self' => 'http://example.com/projects/100',
|
31
|
+
'todolist' => {
|
32
|
+
'linkage' => { 'type' => 'todolists', 'id' => '200' }
|
33
|
+
},
|
34
|
+
'tags' => {
|
35
|
+
'linkage' => [
|
36
|
+
{ 'type' => 'tags', 'id' => '10' }
|
37
|
+
]
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:actual_projects) do
|
45
|
+
SimpleJsonApi.render(
|
46
|
+
model: Project.all.to_a,
|
47
|
+
serializer: ProjectSerializer,
|
48
|
+
page: { number: 5, size: 20, total: 19 }
|
49
|
+
)
|
50
|
+
end
|
51
|
+
let(:expected_projects) do
|
52
|
+
{
|
53
|
+
'links' => {
|
54
|
+
'page' => {
|
55
|
+
'number' => 5,
|
56
|
+
'size' => 20,
|
57
|
+
'total' => 19
|
58
|
+
}
|
59
|
+
},
|
60
|
+
'data' => [
|
61
|
+
{
|
62
|
+
'type' => 'projects',
|
63
|
+
'id' => '100',
|
64
|
+
'name' => 'First Project',
|
65
|
+
'description' => 'The first project',
|
66
|
+
'position' => '',
|
67
|
+
'links' => {
|
68
|
+
'self' => 'http://example.com/projects/100',
|
69
|
+
'todolist' => {
|
70
|
+
'linkage' => { 'type' => 'todolists', 'id' => '200' }
|
71
|
+
},
|
72
|
+
'tags' => {
|
73
|
+
'linkage' => [
|
74
|
+
{ 'type' => 'tags', 'id' => '10' }
|
75
|
+
]
|
76
|
+
}
|
77
|
+
}
|
78
|
+
},
|
79
|
+
{
|
80
|
+
'type' => 'projects',
|
81
|
+
'id' => '110',
|
82
|
+
'name' => 'Second Project',
|
83
|
+
'description' => 'The second project',
|
84
|
+
'position' => '',
|
85
|
+
'links' => {
|
86
|
+
'self' => 'http://example.com/projects/110',
|
87
|
+
'todolist' => {
|
88
|
+
'linkage' => { 'type' => 'todolists', 'id' => '210' }
|
89
|
+
},
|
90
|
+
'tags' => {
|
91
|
+
'linkage' => [
|
92
|
+
{ 'type' => 'tags', 'id' => '20' }
|
93
|
+
]
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
]
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/test/setup/data.rb
CHANGED
@@ -20,7 +20,6 @@ todo1.tags << tag3
|
|
20
20
|
todo2 = list1.todos.create(id: 301, action: 'Bread')
|
21
21
|
todo2.tags << tag1
|
22
22
|
|
23
|
-
|
24
23
|
list2 = project2.create_todolist(id: 210, description: 'Work')
|
25
24
|
list2.todos.create(id: 310, action: 'Timesheet')
|
26
25
|
list2.todos.create(id: 320, action: 'Meeting')
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_json_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gary Gordon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -68,10 +68,6 @@ files:
|
|
68
68
|
- LICENSE.txt
|
69
69
|
- README.md
|
70
70
|
- Rakefile
|
71
|
-
- lib/generators/simple_json_api/resource/USAGE
|
72
|
-
- lib/generators/simple_json_api/resource/resource_generator.rb
|
73
|
-
- lib/generators/simple_json_api/resource/templates/controller_template.rb.erb
|
74
|
-
- lib/generators/simple_json_api/resource/templates/serializer_template.rb.erb
|
75
71
|
- lib/simple_json_api.rb
|
76
72
|
- lib/simple_json_api/api_node.rb
|
77
73
|
- lib/simple_json_api/array_serializer.rb
|
@@ -97,11 +93,11 @@ files:
|
|
97
93
|
- lib/simple_json_api/version.rb
|
98
94
|
- simple_json_api.gemspec
|
99
95
|
- test/fixtures/projects.yml
|
100
|
-
- test/generators/simple_json_api/resource_generator_test.rb
|
101
96
|
- test/integration/render_basic_test.rb
|
102
97
|
- test/integration/render_fields_test.rb
|
103
98
|
- test/integration/render_include_test.rb
|
104
99
|
- test/integration/render_nested_include_test.rb
|
100
|
+
- test/integration/render_pagination_test.rb
|
105
101
|
- test/integration/serializers_test.rb
|
106
102
|
- test/setup/data.rb
|
107
103
|
- test/setup/models.rb
|
@@ -135,17 +131,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
131
|
version: '0'
|
136
132
|
requirements: []
|
137
133
|
rubyforge_project:
|
138
|
-
rubygems_version: 2.4.
|
134
|
+
rubygems_version: 2.4.6
|
139
135
|
signing_key:
|
140
136
|
specification_version: 4
|
141
137
|
summary: A Simple JSON API Serializer.
|
142
138
|
test_files:
|
143
139
|
- test/fixtures/projects.yml
|
144
|
-
- test/generators/simple_json_api/resource_generator_test.rb
|
145
140
|
- test/integration/render_basic_test.rb
|
146
141
|
- test/integration/render_fields_test.rb
|
147
142
|
- test/integration/render_include_test.rb
|
148
143
|
- test/integration/render_nested_include_test.rb
|
144
|
+
- test/integration/render_pagination_test.rb
|
149
145
|
- test/integration/serializers_test.rb
|
150
146
|
- test/setup/data.rb
|
151
147
|
- test/setup/models.rb
|
@@ -1,73 +0,0 @@
|
|
1
|
-
module SimpleJsonApi
|
2
|
-
module Generators
|
3
|
-
# Generates the resource template files
|
4
|
-
class ResourceGenerator < Rails::Generators::NamedBase
|
5
|
-
source_root File.expand_path('../templates', __FILE__)
|
6
|
-
|
7
|
-
argument :name, type: :string, required: true, banner: 'ResourceName'
|
8
|
-
|
9
|
-
class_option :model,
|
10
|
-
desc: 'Model class if different than Resource',
|
11
|
-
type: :string
|
12
|
-
class_option :namespace,
|
13
|
-
desc: 'Namespace for the generated files',
|
14
|
-
type: :string
|
15
|
-
class_option :controller,
|
16
|
-
desc: 'Base controller for resources',
|
17
|
-
type: :string
|
18
|
-
class_option :skip_serializer,
|
19
|
-
desc: "Don't generate a serializer file.",
|
20
|
-
type: :boolean
|
21
|
-
class_option :skip_controller,
|
22
|
-
desc: "Don't generate a controller file.",
|
23
|
-
type: :boolean
|
24
|
-
class_option :skip_service,
|
25
|
-
desc: "Don't generate a service file.",
|
26
|
-
type: :boolean
|
27
|
-
class_option :root_dir,
|
28
|
-
desc: "Root dir for generated code, default: '.'.",
|
29
|
-
type: :string
|
30
|
-
|
31
|
-
def create_resource
|
32
|
-
@namespace = options[:namespace]
|
33
|
-
@model = options[:model] || class_name
|
34
|
-
namespaced_name = [@namespace, class_name].compact.join('::')
|
35
|
-
@serializer_name = "#{namespaced_name}Serializer"
|
36
|
-
@controller_name = "#{namespaced_name.pluralize}Controller"
|
37
|
-
@base_controller = options[:controller] || 'ApplicationController'
|
38
|
-
@root_dir = options[:root_dir] || '.'
|
39
|
-
file_path = "#{@namespace.underscore}/#{class_name.underscore}"
|
40
|
-
|
41
|
-
check_model
|
42
|
-
|
43
|
-
unless options[:skip_serializer]
|
44
|
-
template 'serializer_template.rb.erb',
|
45
|
-
"#{@root_dir}/app/serializers/#{file_path}_serializer.rb"
|
46
|
-
# TODO: create serializer test
|
47
|
-
end
|
48
|
-
|
49
|
-
unless options[:skip_controller]
|
50
|
-
template 'controller_template.rb.erb',
|
51
|
-
"#{@root_dir}/app/controllers/#{file_path.pluralize}_controller.rb"
|
52
|
-
# TODO: create controller test
|
53
|
-
end
|
54
|
-
|
55
|
-
unless options[:skip_service]
|
56
|
-
# TODO: create service
|
57
|
-
# TODO: create service test
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
def check_model
|
64
|
-
unless @model.constantize.ancestors.include?(ActiveRecord::Base)
|
65
|
-
fail NameError
|
66
|
-
end
|
67
|
-
rescue NameError
|
68
|
-
puts "Error: '#{@model}' is not an AR model"
|
69
|
-
exit
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
class <%= @controller_name -%> < <%= @base_controller %>
|
2
|
-
include SimpleJsonApi::Helper
|
3
|
-
|
4
|
-
def index
|
5
|
-
@<%= class_name.underscore.gsub('/', '__').pluralize %> = <%= @model -%>.paginate(page: params[:page], per_page: params[:per_page]).to_a
|
6
|
-
render json: SimpleJsonApi.render(
|
7
|
-
model: @<%= class_name.underscore.gsub('/', '__').pluralize %>,
|
8
|
-
serializer: <%= @serializer_name %>,
|
9
|
-
fields: options_hash.fetch(:fields, nil),
|
10
|
-
include: options_hash.fetch(:include, nil)
|
11
|
-
),
|
12
|
-
status: 200
|
13
|
-
end
|
14
|
-
|
15
|
-
def show
|
16
|
-
@<%= class_name.underscore.gsub('/', '__') %> = <%= @model -%>.find(params[:id])
|
17
|
-
render json: SimpleJsonApi.render(
|
18
|
-
model: @<%= class_name.underscore.gsub('/', '__') %>,
|
19
|
-
serializer: <%= @serializer_name %>,
|
20
|
-
fields: options_hash.fetch(:fields, nil),
|
21
|
-
include: options_hash.fetch(:include, nil)
|
22
|
-
),
|
23
|
-
status: 200
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def options_hash
|
29
|
-
{
|
30
|
-
fields: params[:fields],
|
31
|
-
include: params[:include]
|
32
|
-
}
|
33
|
-
end
|
34
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
class <%= @serializer_name -%> < SimpleJsonApi::ResourceSerializer
|
2
|
-
serializes :<%= class_name.underscore.gsub('/', '__').pluralize %>, model: <%= "::#{@model}" -%>, primary_key: :<%= @model.constantize.primary_key %>
|
3
|
-
|
4
|
-
<%- @model.constantize.column_names.each do |col| -%>
|
5
|
-
attribute :<%= col %>
|
6
|
-
<%- end -%>
|
7
|
-
|
8
|
-
<%- @model.constantize.reflect_on_all_associations.each do |assoc| -%>
|
9
|
-
<%- klass_name = assoc.options[:class_name] -%>
|
10
|
-
<%- serializer = [@namespace, klass_name].compact.join('::') + 'Serializer' if klass_name -%>
|
11
|
-
<%= assoc.macro %> :<%= assoc.name %><%= ', polymorphic: true' if assoc.options[:polymorphic] %><%= ', serializer: ' + serializer if serializer %>
|
12
|
-
<%- end -%>
|
13
|
-
end
|
14
|
-
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'rails/generators'
|
3
|
-
require 'rails/generators/test_case'
|
4
|
-
require 'generators/simple_json_api/resource/resource_generator'
|
5
|
-
|
6
|
-
module SimpleJsonApi
|
7
|
-
module Generators
|
8
|
-
# Tests the generation of the resource template files
|
9
|
-
class ResourceGeneratorTest < Rails::Generators::TestCase
|
10
|
-
tests ResourceGenerator
|
11
|
-
destination 'tmp/generators'
|
12
|
-
setup :prepare_destination
|
13
|
-
|
14
|
-
def test_generator_runs
|
15
|
-
# No error raised? It passes.
|
16
|
-
run_generator %w(Project --namespace=Api::V3)
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_bad_model
|
20
|
-
assert_raises(SystemExit) do
|
21
|
-
run_generator \
|
22
|
-
%w(Project --namespace=Api::V3 --model=ProjectSerializer)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def teardown
|
27
|
-
FileUtils.rm_rf('tmp/generators')
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|