jsonapi_compliable 0.6.13 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -0
- data/docs/Jsonapi/ResourceGenerator.html +325 -0
- data/docs/Jsonapi.html +115 -0
- data/docs/JsonapiCompliable/Adapters/Abstract.html +1 -1
- data/docs/JsonapiCompliable/Adapters/ActiveRecord.html +59 -53
- data/docs/JsonapiCompliable/Adapters/ActiveRecordSideloading.html +6 -6
- data/docs/JsonapiCompliable/Adapters/Null.html +1 -1
- data/docs/JsonapiCompliable/Adapters.html +1 -1
- data/docs/JsonapiCompliable/Base.html +113 -117
- data/docs/JsonapiCompliable/Deserializer.html +87 -22
- data/docs/JsonapiCompliable/Errors/BadFilter.html +1 -1
- data/docs/JsonapiCompliable/Errors/StatNotFound.html +1 -1
- data/docs/JsonapiCompliable/Errors/UnsupportedPageSize.html +1 -1
- data/docs/JsonapiCompliable/Errors/ValidationError.html +1 -1
- data/docs/JsonapiCompliable/Errors.html +1 -1
- data/docs/JsonapiCompliable/Extensions/BooleanAttribute/ClassMethods.html +1 -1
- data/docs/JsonapiCompliable/Extensions/BooleanAttribute.html +1 -1
- data/docs/JsonapiCompliable/Extensions/ExtraAttribute/ClassMethods.html +1 -1
- data/docs/JsonapiCompliable/Extensions/ExtraAttribute.html +1 -1
- data/docs/JsonapiCompliable/Extensions.html +1 -1
- data/docs/JsonapiCompliable/Query.html +19 -17
- data/docs/JsonapiCompliable/Rails.html +1 -1
- data/docs/JsonapiCompliable/Resource.html +311 -220
- data/docs/JsonapiCompliable/Scope.html +1 -1
- data/docs/JsonapiCompliable/Scoping/Base.html +1 -1
- data/docs/JsonapiCompliable/Scoping/DefaultFilter.html +1 -1
- data/docs/JsonapiCompliable/Scoping/ExtraFields.html +1 -1
- data/docs/JsonapiCompliable/Scoping/Filter.html +1 -1
- data/docs/JsonapiCompliable/Scoping/Filterable.html +2 -2
- data/docs/JsonapiCompliable/Scoping/Paginate.html +1 -1
- data/docs/JsonapiCompliable/Scoping/Sort.html +1 -1
- data/docs/JsonapiCompliable/Scoping.html +1 -1
- data/docs/JsonapiCompliable/SerializableTempId.html +1 -1
- data/docs/JsonapiCompliable/Sideload.html +229 -78
- data/docs/JsonapiCompliable/Stats/DSL.html +1 -1
- data/docs/JsonapiCompliable/Stats/Payload.html +1 -1
- data/docs/JsonapiCompliable/Stats.html +1 -1
- data/docs/JsonapiCompliable/Util/FieldParams.html +1 -1
- data/docs/JsonapiCompliable/Util/Hash.html +1 -1
- data/docs/JsonapiCompliable/Util/IncludeParams.html +1 -1
- data/docs/JsonapiCompliable/Util/Persistence.html +1 -1
- data/docs/JsonapiCompliable/Util/RelationshipPayload.html +1 -1
- data/docs/JsonapiCompliable/Util/RenderOptions.html +1 -1
- data/docs/JsonapiCompliable/Util/ValidationResponse.html +1 -1
- data/docs/JsonapiCompliable/Util.html +1 -1
- data/docs/JsonapiCompliable.html +210 -3
- data/docs/_index.html +13 -1
- data/docs/class_list.html +1 -1
- data/docs/file.README.html +4 -2
- data/docs/index.html +4 -2
- data/docs/method_list.html +307 -243
- data/docs/top-level-namespace.html +2 -2
- data/lib/generators/jsonapi/resource_generator.rb +139 -58
- data/lib/generators/jsonapi/templates/application_resource.rb.erb +11 -2
- data/lib/generators/jsonapi/templates/controller.rb.erb +34 -0
- data/lib/generators/jsonapi/templates/destroy_request_spec.rb.erb +1 -1
- data/lib/generators/jsonapi/templates/payload.rb.erb +31 -0
- data/lib/generators/jsonapi/templates/resource.rb.erb +47 -0
- data/lib/generators/jsonapi/templates/serializer.rb.erb +17 -0
- data/lib/jsonapi_compliable/adapters/active_record_sideloading.rb +5 -5
- data/lib/jsonapi_compliable/resource.rb +11 -5
- data/lib/jsonapi_compliable/sideload.rb +40 -11
- data/lib/jsonapi_compliable/util/persistence.rb +9 -2
- data/lib/jsonapi_compliable/util/relationship_payload.rb +6 -0
- data/lib/jsonapi_compliable/util/validation_response.rb +2 -1
- data/lib/jsonapi_compliable/version.rb +1 -1
- metadata +4 -2
@@ -82,7 +82,7 @@
|
|
82
82
|
<p class="children">
|
83
83
|
|
84
84
|
|
85
|
-
<strong class="modules">Modules:</strong> <span class='object_link'><a href="JsonapiCompliable.html" title="JsonapiCompliable (module)">JsonapiCompliable</a></span>
|
85
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Jsonapi.html" title="Jsonapi (module)">Jsonapi</a></span>, <span class='object_link'><a href="JsonapiCompliable.html" title="JsonapiCompliable (module)">JsonapiCompliable</a></span>
|
86
86
|
|
87
87
|
|
88
88
|
|
@@ -100,7 +100,7 @@
|
|
100
100
|
</div>
|
101
101
|
|
102
102
|
<div id="footer">
|
103
|
-
Generated on
|
103
|
+
Generated on Wed Jun 7 10:15:09 2017 by
|
104
104
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
105
105
|
0.9.9 (ruby-2.3.0).
|
106
106
|
</div>
|
@@ -2,85 +2,166 @@ module Jsonapi
|
|
2
2
|
class ResourceGenerator < ::Rails::Generators::NamedBase
|
3
3
|
source_root File.expand_path('../templates', __FILE__)
|
4
4
|
|
5
|
-
class_option :'
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
class_option :'omit-comments',
|
6
|
+
type: :boolean,
|
7
|
+
default: false,
|
8
|
+
aliases: ['--omit-comments', '-c'],
|
9
|
+
desc: 'Generate without documentation comments'
|
10
|
+
class_option :'omit-controller',
|
11
|
+
type: :boolean,
|
12
|
+
default: false,
|
13
|
+
aliases: ['--omit-controller'],
|
14
|
+
desc: 'Generate without controller'
|
15
|
+
class_option :'omit-serializer',
|
16
|
+
type: :boolean,
|
17
|
+
default: false,
|
18
|
+
aliases: ['--omit-serializer', '-s'],
|
19
|
+
desc: 'Generate without serializer'
|
20
|
+
class_option :'omit-payload',
|
21
|
+
type: :boolean,
|
22
|
+
default: false,
|
23
|
+
aliases: ['--omit-payload', '-p'],
|
24
|
+
desc: 'Generate without spec payload'
|
25
|
+
class_option :'omit-strong-resource',
|
26
|
+
type: :boolean,
|
27
|
+
default: false,
|
28
|
+
aliases: ['--omit-strong-resource', '-r'],
|
29
|
+
desc: 'Generate without strong resource'
|
30
|
+
class_option :'omit-route',
|
31
|
+
type: :boolean,
|
32
|
+
default: false,
|
33
|
+
aliases: ['--omit-route'],
|
34
|
+
desc: 'Generate without specs'
|
35
|
+
class_option :'omit-tests',
|
36
|
+
type: :boolean,
|
37
|
+
default: false,
|
38
|
+
aliases: ['--omit-tests', '-t'],
|
39
|
+
desc: 'Generate without specs'
|
40
|
+
|
41
|
+
desc "This generator creates a resource file at app/resources, as well as corresponding controller/specs/route/etc"
|
12
42
|
def copy_resource_file
|
13
|
-
unless
|
14
|
-
|
15
|
-
template('controller.rb.erb', to)
|
43
|
+
unless model_klass
|
44
|
+
raise "You must define a #{class_name} model before generating the corresponding resource."
|
16
45
|
end
|
17
46
|
|
18
|
-
unless
|
19
|
-
|
20
|
-
|
21
|
-
|
47
|
+
generate_controller unless omit_controller?
|
48
|
+
generate_serializer unless omit_serializer?
|
49
|
+
generate_application_resource unless application_resource_defined?
|
50
|
+
generate_spec_payload unless omit_spec_payload?
|
51
|
+
generate_strong_resource unless omit_strong_resource?
|
52
|
+
generate_route unless omit_route?
|
53
|
+
generate_tests unless omit_tests?
|
54
|
+
generate_resource
|
55
|
+
end
|
22
56
|
|
23
|
-
|
24
|
-
to = File.join('app/resources', class_path, "application_resource.rb")
|
25
|
-
template('application_resource.rb.erb', to)
|
26
|
-
end
|
57
|
+
private
|
27
58
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
59
|
+
def omit_comments?
|
60
|
+
@options['omit-comments']
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate_controller
|
64
|
+
to = File.join('app/controllers', class_path, "#{file_name.pluralize}_controller.rb")
|
65
|
+
template('controller.rb.erb', to)
|
66
|
+
end
|
32
67
|
|
33
|
-
|
34
|
-
|
68
|
+
def omit_controller?
|
69
|
+
@options['omit-controller']
|
70
|
+
end
|
71
|
+
|
72
|
+
def generate_serializer
|
73
|
+
to = File.join('app/serializers', class_path, "serializable_#{file_name}.rb")
|
74
|
+
template('serializer.rb.erb', to)
|
75
|
+
end
|
76
|
+
|
77
|
+
def omit_serializer?
|
78
|
+
@options['omit-serializer']
|
79
|
+
end
|
80
|
+
|
81
|
+
def generate_application_resource
|
82
|
+
to = File.join('app/resources', class_path, "application_resource.rb")
|
83
|
+
template('application_resource.rb.erb', to)
|
84
|
+
end
|
85
|
+
|
86
|
+
def application_resource_defined?
|
87
|
+
'ApplicationResource'.safe_constantize.present?
|
88
|
+
end
|
89
|
+
|
90
|
+
def generate_spec_payload
|
91
|
+
to = File.join('spec/payloads', class_path, "#{file_name}.rb")
|
92
|
+
template('payload.rb.erb', to)
|
93
|
+
end
|
94
|
+
|
95
|
+
def omit_spec_payload?
|
96
|
+
@options['no-payload']
|
97
|
+
end
|
98
|
+
|
99
|
+
def generate_strong_resource
|
100
|
+
code = <<-STR
|
35
101
|
strong_resource :#{file_name} do
|
36
102
|
# Your attributes go here, e.g.
|
37
103
|
# attribute :name, :string
|
38
104
|
end
|
39
105
|
|
40
|
-
|
41
|
-
|
106
|
+
STR
|
107
|
+
inject_into_file 'config/initializers/strong_resources.rb', after: "StrongResources.configure do\n" do
|
108
|
+
code
|
42
109
|
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def omit_strong_resource?
|
113
|
+
@options['no-strong-resources']
|
114
|
+
end
|
43
115
|
|
44
|
-
|
45
|
-
|
116
|
+
def generate_route
|
117
|
+
code = <<-STR
|
46
118
|
resources :#{type}
|
47
|
-
|
48
|
-
|
119
|
+
STR
|
120
|
+
inject_into_file 'config/routes.rb', after: "scope path: '/api' do\n scope path: '/v1' do\n" do
|
121
|
+
code
|
49
122
|
end
|
123
|
+
end
|
50
124
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
125
|
+
def omit_route?
|
126
|
+
@options['no-route']
|
127
|
+
end
|
128
|
+
|
129
|
+
def generate_tests
|
130
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
131
|
+
class_path,
|
132
|
+
"index_spec.rb"
|
133
|
+
template('index_request_spec.rb.erb', to)
|
134
|
+
|
135
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
136
|
+
class_path,
|
137
|
+
"show_spec.rb"
|
138
|
+
template('show_request_spec.rb.erb', to)
|
139
|
+
|
140
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
141
|
+
class_path,
|
142
|
+
"create_spec.rb"
|
143
|
+
template('create_request_spec.rb.erb', to)
|
144
|
+
|
145
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
146
|
+
class_path,
|
147
|
+
"update_spec.rb"
|
148
|
+
template('update_request_spec.rb.erb', to)
|
149
|
+
|
150
|
+
to = File.join "spec/api/v1/#{file_name.pluralize}",
|
151
|
+
class_path,
|
152
|
+
"destroy_spec.rb"
|
153
|
+
template('destroy_request_spec.rb.erb', to)
|
154
|
+
end
|
77
155
|
|
156
|
+
def omit_tests?
|
157
|
+
@options['no-test']
|
158
|
+
end
|
159
|
+
|
160
|
+
def generate_resource
|
78
161
|
to = File.join('app/resources', class_path, "#{file_name}_resource.rb")
|
79
162
|
template('resource.rb.erb', to)
|
80
163
|
end
|
81
164
|
|
82
|
-
private
|
83
|
-
|
84
165
|
def model_klass
|
85
166
|
class_name.safe_constantize
|
86
167
|
end
|
@@ -1,5 +1,14 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
<%- unless omit_comments? -%>
|
2
|
+
# ApplicationResource is similar to ApplicationRecord - a base class that
|
3
|
+
# holds configuration/methods for subclasses.
|
4
|
+
# All Resources should inherit from ApplicationResource.
|
5
|
+
# Resource documentation: https://jsonapi-suite.github.io/jsonapi_compliable/JsonapiCompliable/Resource.html
|
6
|
+
<%- end -%>
|
3
7
|
class ApplicationResource < JsonapiCompliable::Resource
|
8
|
+
<%- unless omit_comments? -%>
|
9
|
+
# Use the ActiveRecord Adapter for all subclasses.
|
10
|
+
# Subclasses can still override this default.
|
11
|
+
# More on adapters: https://jsonapi-suite.github.io/jsonapi_compliable/JsonapiCompliable/Adapters/Abstract.html
|
12
|
+
<%- end -%>
|
4
13
|
use_adapter JsonapiCompliable::Adapters::ActiveRecord
|
5
14
|
end
|
@@ -1,21 +1,46 @@
|
|
1
1
|
<% module_namespacing do -%>
|
2
2
|
class <%= model_klass.name.pluralize %>Controller < ApplicationController
|
3
|
+
<%- unless omit_comments? -%>
|
4
|
+
# Mark this as a JSONAPI controller, associating with the given resource
|
5
|
+
<%- end -%>
|
3
6
|
jsonapi resource: <%= model_klass %>Resource
|
4
7
|
|
8
|
+
<%- unless omit_comments? -%>
|
9
|
+
# Reference a strong resource payload defined in
|
10
|
+
# config/initializers/strong_resources.rb
|
11
|
+
<%- end -%>
|
5
12
|
strong_resource :<%= file_name %>
|
6
13
|
|
14
|
+
<%- unless omit_comments? -%>
|
15
|
+
# Run strong parameter validation for these actions.
|
16
|
+
# Invalid keys will be dropped.
|
17
|
+
# Invalid value types will log or raise based on the configuration
|
18
|
+
# ActionController::Parameters.action_on_invalid_parameters
|
19
|
+
<%- end -%>
|
7
20
|
before_action :apply_strong_params, only: [:create, :update]
|
8
21
|
|
22
|
+
<%- unless omit_comments? -%>
|
23
|
+
# Start with a base scope and pass to render_jsonapi
|
24
|
+
<%- end -%>
|
9
25
|
def index
|
10
26
|
<%= file_name.pluralize %> = <%= model_klass %>.all
|
11
27
|
render_jsonapi(<%= file_name.pluralize %>)
|
12
28
|
end
|
13
29
|
|
30
|
+
<%- unless omit_comments? -%>
|
31
|
+
# Call jsonapi_scope directly here so we can get behavior like
|
32
|
+
# sparse fieldsets and statistics.
|
33
|
+
<%- end -%>
|
14
34
|
def show
|
15
35
|
scope = jsonapi_scope(<%= model_klass %>.where(id: params[:id]))
|
16
36
|
render_jsonapi(scope.resolve.first, scope: false)
|
17
37
|
end
|
18
38
|
|
39
|
+
<%- unless omit_comments? -%>
|
40
|
+
# jsonapi_create will use the configured Resource (and adapter) to persist.
|
41
|
+
# This will handle nested relationships as well.
|
42
|
+
# On validation errors, render correct error JSON.
|
43
|
+
<%- end -%>
|
19
44
|
def create
|
20
45
|
<%= file_name %>, success = jsonapi_create.to_a
|
21
46
|
|
@@ -26,6 +51,11 @@ class <%= model_klass.name.pluralize %>Controller < ApplicationController
|
|
26
51
|
end
|
27
52
|
end
|
28
53
|
|
54
|
+
<%- unless omit_comments? -%>
|
55
|
+
# jsonapi_update will use the configured Resource (and adapter) to persist.
|
56
|
+
# This will handle nested relationships as well.
|
57
|
+
# On validation errors, render correct error JSON.
|
58
|
+
<%- end -%>
|
29
59
|
def update
|
30
60
|
<%= file_name %>, success = jsonapi_update.to_a
|
31
61
|
|
@@ -36,6 +66,10 @@ class <%= model_klass.name.pluralize %>Controller < ApplicationController
|
|
36
66
|
end
|
37
67
|
end
|
38
68
|
|
69
|
+
<%- unless omit_comments? -%>
|
70
|
+
# No need for any special logic here as no_content is jsonapi_compliant.
|
71
|
+
# Customize this if you have a more complex use case.
|
72
|
+
<%- end -%>
|
39
73
|
def destroy
|
40
74
|
<%= file_name %> = <%= model_klass %>.find(params[:id])
|
41
75
|
<%= file_name %>.destroy
|
@@ -2,7 +2,7 @@ require 'rails_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe "<%= type %>#destroy", type: :request do
|
4
4
|
context 'basic destroy' do
|
5
|
-
let!(:<%= file_name %>) { create(:<%= file_name %>) }
|
5
|
+
let!(:<%= file_name %>) { FactoryGirl.create(:<%= file_name %>) }
|
6
6
|
|
7
7
|
it 'updates the resource' do
|
8
8
|
expect {
|
@@ -1,2 +1,33 @@
|
|
1
|
+
<%- unless omit_comments? -%>
|
2
|
+
# Register a payload to validate against.
|
3
|
+
# Add expected attributes within this block, e.g.:
|
4
|
+
#
|
5
|
+
# key(:name)
|
6
|
+
#
|
7
|
+
# Optionally validate the type as well:
|
8
|
+
#
|
9
|
+
# key(:name, String)
|
10
|
+
#
|
11
|
+
# This will:
|
12
|
+
#
|
13
|
+
# * Compare record.name == json['name']
|
14
|
+
# * Ensure no extra keys are in the json payload
|
15
|
+
# * Ensure no values are nil (unless allow_nil: true is passed)
|
16
|
+
# * Ensures json['name'] is a string
|
17
|
+
#
|
18
|
+
# If you have custom serialization logic and want to compare against
|
19
|
+
# something other than "record.name", pass a block:
|
20
|
+
#
|
21
|
+
# key(:name) { |record| record.name.upcase }
|
22
|
+
#
|
23
|
+
# Or, if this is a one-off for a particular spec, do that customization at
|
24
|
+
# runtime:
|
25
|
+
#
|
26
|
+
# assert_payload(:person, person_record, json_item) do
|
27
|
+
# key(:name) { 'Homer Simpson' }
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# For more information, see https://jsonapi-suite.github.io/jsonapi_spec_helpers/
|
31
|
+
<%- end -%>
|
1
32
|
JsonapiSpecHelpers::Payload.register(:<%= file_name %>) do
|
2
33
|
end
|
@@ -1,6 +1,53 @@
|
|
1
|
+
<%- unless omit_comments? -%>
|
2
|
+
# Define how to query and persist a given model.
|
3
|
+
# Further Resource documentation: https://jsonapi-suite.github.io/jsonapi_compliable/JsonapiCompliable/Resource.html
|
4
|
+
<%- end -%>
|
1
5
|
<% module_namespacing do -%>
|
2
6
|
class <%= class_name %>Resource < ApplicationResource
|
7
|
+
<%- unless omit_comments? -%>
|
8
|
+
# Used for associating this resource with a given input.
|
9
|
+
# This should match the 'type' in the corresponding serializer.
|
10
|
+
<%- end -%>
|
3
11
|
type :<%= type %>
|
12
|
+
<%- unless omit_comments? -%>
|
13
|
+
# Associate to a Model object so we know how to persist.
|
14
|
+
<%- end -%>
|
4
15
|
model <%= model_klass %>
|
16
|
+
<%- unless omit_comments? -%>
|
17
|
+
# Customize your resource here. Some common examples:
|
18
|
+
#
|
19
|
+
# === Allow ?filter[name] query parameter ===
|
20
|
+
# allow_filter :name
|
21
|
+
#
|
22
|
+
# === Enable total count, when requested ===
|
23
|
+
# allow_stat total: [:count]
|
24
|
+
#
|
25
|
+
# === Allow sideloading/sideposting of relationships ===
|
26
|
+
# belongs_to :foo,
|
27
|
+
# foreign_key: :foo_id,
|
28
|
+
# resource: FooResource,
|
29
|
+
# scope: -> { Foo.all }
|
30
|
+
#
|
31
|
+
# === Custom sorting logic ===
|
32
|
+
# sort do |scope, att, dir|
|
33
|
+
# ... code ...
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# === Change default sort ===
|
37
|
+
# default_sort([{ title: :asc }])
|
38
|
+
#
|
39
|
+
# === Custom pagination logic ===
|
40
|
+
# paginate do |scope, current_page, per_page|
|
41
|
+
# ... code ...
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# === Change default page size ===
|
45
|
+
# default_page_size(10)
|
46
|
+
#
|
47
|
+
# === Change how we resolve the scope ===
|
48
|
+
# def resolve(scope)
|
49
|
+
# ... code ...
|
50
|
+
# end
|
51
|
+
<%- end -%>
|
5
52
|
end
|
6
53
|
<% end -%>
|
@@ -1,5 +1,22 @@
|
|
1
|
+
<%- unless omit_comments? -%>
|
2
|
+
# Serializers define the rendered JSON for a model instance.
|
3
|
+
# We use jsonapi-rb, which is similar to active_model_serializers.
|
4
|
+
<%- end -%>
|
1
5
|
<% module_namespacing do -%>
|
2
6
|
class Serializable<%= class_name %> < JSONAPI::Serializable::Resource
|
3
7
|
type :<%= type %>
|
8
|
+
|
9
|
+
<%- unless omit_comments? -%>
|
10
|
+
# Add attributes here to ensure they get rendered, .e.g.
|
11
|
+
#
|
12
|
+
# attribute :name
|
13
|
+
#
|
14
|
+
# To customize, pass a block and reference the underlying @object
|
15
|
+
# being serialized:
|
16
|
+
#
|
17
|
+
# attribute :name do
|
18
|
+
# @object.name.upcase
|
19
|
+
# end
|
20
|
+
<%- end -%>
|
4
21
|
end
|
5
22
|
<% end -%>
|
@@ -47,7 +47,7 @@ module JsonapiCompliable
|
|
47
47
|
def has_one(association_name, scope: nil, resource:, foreign_key:, primary_key: :id, &blk)
|
48
48
|
_scope = scope
|
49
49
|
|
50
|
-
allow_sideload association_name, resource: resource do
|
50
|
+
allow_sideload association_name, type: :has_one, foreign_key: foreign_key, primary_key: primary_key, resource: resource do
|
51
51
|
scope do |parents|
|
52
52
|
parent_ids = parents.map { |p| p.send(primary_key) }
|
53
53
|
_scope.call.where(foreign_key => parent_ids.uniq.compact)
|
@@ -71,7 +71,7 @@ module JsonapiCompliable
|
|
71
71
|
fk = foreign_key.values.first
|
72
72
|
_scope = scope
|
73
73
|
|
74
|
-
allow_sideload association_name, resource: resource do
|
74
|
+
allow_sideload association_name, type: :habtm, foreign_key: foreign_key, primary_key: primary_key, resource: resource do
|
75
75
|
scope do |parents|
|
76
76
|
parent_ids = parents.map { |p| p.send(primary_key) }
|
77
77
|
parent_ids.uniq!
|
@@ -94,14 +94,14 @@ module JsonapiCompliable
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def polymorphic_belongs_to(association_name, group_by:, groups:, &blk)
|
97
|
-
allow_sideload association_name, polymorphic: true do
|
98
|
-
group_by(
|
97
|
+
allow_sideload association_name, type: :polymorphic_belongs_to, polymorphic: true do
|
98
|
+
group_by(group_by)
|
99
99
|
|
100
100
|
groups.each_pair do |type, config|
|
101
101
|
primary_key = config[:primary_key] || :id
|
102
102
|
foreign_key = config[:foreign_key]
|
103
103
|
|
104
|
-
allow_sideload type, resource: config[:resource] do
|
104
|
+
allow_sideload type, parent: self, primary_key: primary_key, foreign_key: foreign_key, type: :belongs_to, resource: config[:resource] do
|
105
105
|
scope do |parents|
|
106
106
|
parent_ids = parents.map { |p| p.send(foreign_key) }
|
107
107
|
parent_ids.compact!
|
@@ -87,8 +87,6 @@ module JsonapiCompliable
|
|
87
87
|
# scope: -> { Comment.all },
|
88
88
|
# resource: CommentResource,
|
89
89
|
# foreign_key: :post_id
|
90
|
-
#
|
91
|
-
# @attr_reader [Hash] context A hash of +object+ and +namespace+ - Example object is a Rails controller, example namespace would be +:index+ or +:show+
|
92
90
|
class Resource
|
93
91
|
extend Forwardable
|
94
92
|
attr_reader :context
|
@@ -451,16 +449,24 @@ module JsonapiCompliable
|
|
451
449
|
end
|
452
450
|
end
|
453
451
|
|
454
|
-
# The current context set by +#with_context
|
452
|
+
# The current context **object** set by +#with_context+. If you are
|
453
|
+
# using Rails, this is a controller instance.
|
455
454
|
#
|
456
|
-
#
|
455
|
+
# This method is equivalent to +JsonapiCompliable.context[:object]+
|
457
456
|
#
|
458
457
|
# @see #with_context
|
459
|
-
# @return
|
458
|
+
# @return the context object
|
460
459
|
def context
|
461
460
|
JsonapiCompliable.context[:object]
|
462
461
|
end
|
463
462
|
|
463
|
+
# The current context **namespace** set by +#with_context+. If you
|
464
|
+
# are using Rails, this is the controller method name (e.g. +:index+)
|
465
|
+
#
|
466
|
+
# This method is equivalent to +JsonapiCompliable.context[:namespace]+
|
467
|
+
#
|
468
|
+
# @see #with_context
|
469
|
+
# @return [Symbol] the context namespace
|
464
470
|
def context_namespace
|
465
471
|
JsonapiCompliable.context[:namespace]
|
466
472
|
end
|
@@ -6,7 +6,7 @@ module JsonapiCompliable
|
|
6
6
|
# @attr_reader [Hash] sideloads The associated sibling sideloads
|
7
7
|
# @attr_reader [Proc] scope_proc The configured 'scope' block
|
8
8
|
# @attr_reader [Proc] assign_proc The configured 'assign' block
|
9
|
-
# @attr_reader [
|
9
|
+
# @attr_reader [Symbol] grouping_field The configured 'group_by' symbol
|
10
10
|
# @attr_reader [Symbol] foreign_key The attribute used to match objects - need not be a true database foreign key.
|
11
11
|
# @attr_reader [Symbol] primary_key The attribute used to match objects - need not be a true database primary key.
|
12
12
|
# @attr_reader [Symbol] type One of :has_many, :belongs_to, etc
|
@@ -15,10 +15,11 @@ module JsonapiCompliable
|
|
15
15
|
:resource_class,
|
16
16
|
:polymorphic,
|
17
17
|
:polymorphic_groups,
|
18
|
+
:parent,
|
18
19
|
:sideloads,
|
19
20
|
:scope_proc,
|
20
21
|
:assign_proc,
|
21
|
-
:
|
22
|
+
:grouping_field,
|
22
23
|
:foreign_key,
|
23
24
|
:primary_key,
|
24
25
|
:type
|
@@ -28,12 +29,13 @@ module JsonapiCompliable
|
|
28
29
|
# An anonymous Resource will be assigned when none provided.
|
29
30
|
#
|
30
31
|
# @see Adapters::Abstract#sideloading_module
|
31
|
-
def initialize(name, type: nil, resource: nil, polymorphic: false, primary_key: :id, foreign_key: nil)
|
32
|
+
def initialize(name, type: nil, resource: nil, polymorphic: false, primary_key: :id, foreign_key: nil, parent: nil)
|
32
33
|
@name = name
|
33
34
|
@resource_class = (resource || Class.new(Resource))
|
34
35
|
@sideloads = {}
|
35
36
|
@polymorphic = !!polymorphic
|
36
37
|
@polymorphic_groups = {} if polymorphic?
|
38
|
+
@parent = parent
|
37
39
|
@primary_key = primary_key
|
38
40
|
@foreign_key = foreign_key
|
39
41
|
@type = type
|
@@ -55,7 +57,7 @@ module JsonapiCompliable
|
|
55
57
|
# +Business+ or +Government+:
|
56
58
|
#
|
57
59
|
# allow_sideload :organization, :polymorphic: true do
|
58
|
-
# group_by
|
60
|
+
# group_by :organization_type
|
59
61
|
#
|
60
62
|
# allow_sideload 'Business', resource: BusinessResource do
|
61
63
|
# # ... code ...
|
@@ -70,7 +72,7 @@ module JsonapiCompliable
|
|
70
72
|
# with ActiveRecord:
|
71
73
|
#
|
72
74
|
# polymorphic_belongs_to :organization,
|
73
|
-
# group_by:
|
75
|
+
# group_by: :organization_type,
|
74
76
|
# groups: {
|
75
77
|
# 'Business' => {
|
76
78
|
# scope: -> { Business.all },
|
@@ -181,21 +183,25 @@ module JsonapiCompliable
|
|
181
183
|
# @see #name
|
182
184
|
# @see #type
|
183
185
|
def associate(parent, child)
|
184
|
-
|
186
|
+
association_name = @parent ? @parent.name : name
|
187
|
+
resource_class.config[:adapter].associate parent,
|
188
|
+
child,
|
189
|
+
association_name,
|
190
|
+
type
|
185
191
|
end
|
186
192
|
|
187
|
-
# Define
|
193
|
+
# Define an attribute that groups the parent records. For instance, with
|
188
194
|
# an ActiveRecord polymorphic belongs_to there will be a +parent_id+
|
189
195
|
# and +parent_type+. We would want to group on +parent_type+:
|
190
196
|
#
|
191
197
|
# allow_sideload :organization, polymorphic: true do
|
192
198
|
# # group parent_type, parent here is 'organization'
|
193
|
-
# group_by
|
199
|
+
# group_by :organization_type
|
194
200
|
# end
|
195
201
|
#
|
196
202
|
# @see #polymorphic?
|
197
|
-
def group_by(
|
198
|
-
@
|
203
|
+
def group_by(grouping_field)
|
204
|
+
@grouping_field = grouping_field
|
199
205
|
end
|
200
206
|
|
201
207
|
# Resolve the sideload.
|
@@ -323,6 +329,13 @@ module JsonapiCompliable
|
|
323
329
|
result
|
324
330
|
end
|
325
331
|
|
332
|
+
# @api private
|
333
|
+
def polymorphic_child_for_type(type)
|
334
|
+
polymorphic_groups.values.find do |v|
|
335
|
+
v.resource_class.config[:type] == type.to_sym
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
326
339
|
private
|
327
340
|
|
328
341
|
def nested_sideload_hash(sideload, processed)
|
@@ -333,8 +346,24 @@ module JsonapiCompliable
|
|
333
346
|
end
|
334
347
|
end
|
335
348
|
|
349
|
+
def polymorphic_grouper(grouping_field)
|
350
|
+
lambda do |record|
|
351
|
+
if record.is_a?(Hash)
|
352
|
+
if record.keys[0].is_a?(Symbol)
|
353
|
+
record[grouping_field]
|
354
|
+
else
|
355
|
+
record[grouping_field.to_s]
|
356
|
+
end
|
357
|
+
else
|
358
|
+
record.send(grouping_field)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
336
363
|
def resolve_polymorphic(parents, query)
|
337
|
-
|
364
|
+
grouper = polymorphic_grouper(@grouping_field)
|
365
|
+
|
366
|
+
parents.group_by(&grouper).each_pair do |group_type, group_members|
|
338
367
|
sideload_for_group = @polymorphic_groups[group_type]
|
339
368
|
if sideload_for_group
|
340
369
|
sideload_for_group.resolve(group_members, query, name)
|