jsonapi_parameters 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f3245b44f39068e448c0acbf8ad822ebe3891133cfde009c4b6411d3b9a50f1b
4
- data.tar.gz: cfc79502f187a3f9453f9b3ba952128e00114a7cc47ea5aaf6047ba5484c49cc
3
+ metadata.gz: 02a88091cd1b68f0f385e97308b9b5ed213fe640f5f4831d0e83227cbb24fc98
4
+ data.tar.gz: 56dc70b94dac08359d21703245e1f5a8b7864bf9a0ec4b487b68057121fcac60
5
5
  SHA512:
6
- metadata.gz: 1f2504172943defbcd2bfbd86eca1134ca2da0193f6f89e0f315ba931372864b545e9005266251982c0e6b167e004a8202a1ca95954837b1b1796e7f4148897b
7
- data.tar.gz: f13ad5d8f443e1cd010c133152b50791d876c44b32385d4009318b94e4f29c437d55a02882737bc57237d171e68f8f1802d52976596d13bd0cf60167cc9403ea
6
+ metadata.gz: b2ec520d45378a5c44c59f6eb37fd2d809e200eb0203d200d3b388a94dbfacfe0dfab9c1578f5ea446aba52de63deeb618e7baf9263c38573ac406cdedadf9bf
7
+ data.tar.gz: e9a193c2d58b04be662ae0481d9dc1ff451dbd49b44f7d4b18f0698b99c1958e843c66cb8659bf304db8ed649ac996643738dc6041f466ebc15492f2b330d5cf
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # JsonApi::Parameters
2
2
  Simple JSON:API compliant parameters translator.
3
3
 
4
+ [![Gem Version](https://badge.fury.io/rb/jsonapi_parameters.svg)](https://badge.fury.io/rb/jsonapi_parameters)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/84fd5b548eea8d7e18af/maintainability)](https://codeclimate.com/github/visualitypl/jsonapi_parameters/maintainability)
6
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/84fd5b548eea8d7e18af/test_coverage)](https://codeclimate.com/github/visualitypl/jsonapi_parameters/test_coverage)
7
+
4
8
  #### The problem
5
9
 
6
10
  JSON:API standard specifies not only responses (that can be handled nicely, using gems like [fast_jsonapi from Netflix](https://github.com/Netflix/fast_jsonapi)), but also the request structure.
@@ -60,6 +64,209 @@ def create_params
60
64
  end
61
65
  ```
62
66
 
67
+ #### Relationships
68
+
69
+ JsonApi::Parameters supports ActiveRecord relationship parameters, including [nested attributes](https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html).
70
+
71
+ Relationship parameters are being read from two optional trees:
72
+
73
+ * `relationships`,
74
+ * `included`
75
+
76
+ If you provide any related resources in the `relationships` table, this gem will also look for corresponding, `included` resources and their attributes. Thanks to that this gem supports nested attributes, and will try to translate these included resources and pass them along.
77
+
78
+ ##### belongs_to
79
+
80
+ Passing a resource that is a single entity in relationships tree will make JsonApi::Parameters assume that it is a `belongs_to` relationship.
81
+
82
+ ###### Without included entity
83
+ Example:
84
+
85
+ ```
86
+ class Movie < ActiveRecord::Model
87
+ belongs_to :director
88
+ end
89
+ ```
90
+
91
+ Request body:
92
+
93
+ ```
94
+ {
95
+ data: {
96
+ type: 'movies',
97
+ attributes: {
98
+ title: 'The Terminator',
99
+ },
100
+ relationships: {
101
+ director: {
102
+ data: {
103
+ id: 682, type: 'directors'
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ ```
110
+
111
+ Will translate to:
112
+
113
+ ```
114
+ {
115
+ movie: {
116
+ title: 'The Terminator',
117
+ director_id: 682
118
+ }
119
+ }
120
+ ```
121
+
122
+
123
+ ###### With included entity:
124
+ Example:
125
+
126
+ ```
127
+ class Movie < ActiveRecord::Model
128
+ belongs_to :director
129
+
130
+ accepts_nested_attributes_for :director
131
+ end
132
+ ```
133
+
134
+ Request body:
135
+ ```
136
+ {
137
+ data: {
138
+ type: 'movies',
139
+ attributes: {
140
+ title: 'The Terminator',
141
+ },
142
+ relationships: {
143
+ director: {
144
+ data: {
145
+ id: 682, type: 'directors'
146
+ }
147
+ }
148
+ }
149
+ },
150
+ included: [
151
+ {
152
+ type: 'directors',
153
+ id: 682,
154
+ attributes: {
155
+ name: 'Some guy'
156
+ }
157
+ }
158
+ ]
159
+ }
160
+ ```
161
+
162
+ Will translate to:
163
+ ```
164
+ {
165
+ movie: {
166
+ title: 'The Terminator',
167
+ director_attributes: { id: 682, name: 'Some guy' }
168
+ }
169
+ }
170
+ ```
171
+
172
+ ##### has_many
173
+
174
+ Passing a resource that is a an array of entities in relationships tree will make JsonApi::Parameters assume that it is a `has_many` relationship.
175
+
176
+ ###### Without included entity
177
+ Example:
178
+
179
+ ```
180
+ class Movie < ActiveRecord::Model
181
+ has_many :genres
182
+ end
183
+ ```
184
+
185
+ Request body:
186
+
187
+ ```
188
+ {
189
+ data: {
190
+ type: 'movies',
191
+ attributes: {
192
+ title: 'The Terminator',
193
+ },
194
+ relationships: {
195
+ genres: [{
196
+ data: {
197
+ id: 1, type: 'genres'
198
+ },
199
+ data: {
200
+ id: 2, type: 'genres'
201
+ },
202
+ }]
203
+ }
204
+ }
205
+ }
206
+ ```
207
+
208
+ Will translate to:
209
+
210
+ ```
211
+ {
212
+ movie: {
213
+ title: 'The Terminator',
214
+ genre_ids: [1, 2]
215
+ }
216
+ }
217
+ ```
218
+
219
+
220
+ ###### With included entity:
221
+ Example:
222
+
223
+ ```
224
+ class Movie < ActiveRecord::Model
225
+ has_many :genres
226
+
227
+ accepts_nested_attributes_for :genres
228
+ end
229
+ ```
230
+
231
+ Request body:
232
+ ```
233
+ {
234
+ data: {
235
+ type: 'movies',
236
+ attributes: {
237
+ title: 'The Terminator',
238
+ },
239
+ relationships: {
240
+ genres: [{
241
+ data: {
242
+ id: 1, type: 'genres'
243
+ }
244
+ }]
245
+ }
246
+ },
247
+ included: [
248
+ {
249
+ type: 'genre',
250
+ id: 1,
251
+ attributes: {
252
+ name: 'Genre one'
253
+ }
254
+ }
255
+ ]
256
+ }
257
+ ```
258
+
259
+ Will translate to:
260
+ ```
261
+ {
262
+ movie: {
263
+ title: 'The Terminator',
264
+ genres_attributes: [{ id: 1, name: 'Genre one' }]
265
+ }
266
+ }
267
+ ```
268
+
269
+
63
270
  #### Casing
64
271
 
65
272
  If the input is in a different convention than `:snake`, you should specify that.
data/Rakefile CHANGED
@@ -15,13 +15,6 @@ RDoc::Task.new(:rdoc) do |rdoc|
15
15
  end
16
16
 
17
17
  require 'bundler/gem_tasks'
18
+ require 'rspec/core/rake_task'
18
19
 
19
- require 'rake/testtask'
20
-
21
- Rake::TestTask.new(:test) do |t|
22
- t.libs << 'test'
23
- t.pattern = 'test/**/*_test.rb'
24
- t.verbose = false
25
- end
26
-
27
- task default: :test
20
+ task :default => :spec
@@ -2,3 +2,5 @@ require 'jsonapi_parameters/parameters'
2
2
  require 'jsonapi_parameters/translator'
3
3
  require 'jsonapi_parameters/core_ext'
4
4
  require 'jsonapi_parameters/version'
5
+
6
+ require 'active_support/inflector'
@@ -1,2 +1,2 @@
1
- require_relative 'core_ext/action_controller/parameters'
2
- require_relative 'core_ext/action_dispatch/http/mime_type'
1
+ require 'jsonapi_parameters/core_ext/action_controller/parameters'
2
+ require 'jsonapi_parameters/core_ext/action_dispatch/http/mime_type'
@@ -1,4 +1,6 @@
1
1
  module JsonApi::Parameters
2
+ include ActiveSupport::Inflector
3
+
2
4
  def jsonapify(params, naming_convention: :snake)
3
5
  jsonapi_translate(params, naming_convention: naming_convention)
4
6
  end
@@ -60,9 +62,9 @@ module JsonApi::Parameters
60
62
  end
61
63
 
62
64
  def handle_to_many_relation(relationship_key, relationship_value)
63
- key = "#{relationship_key.to_s.pluralize}_attributes".to_sym
65
+ with_inclusion = true
64
66
 
65
- val = relationship_value.map do |relationship_value|
67
+ vals = relationship_value.map do |relationship_value|
66
68
  related_id = relationship_value.dig(:id)
67
69
  related_type = relationship_value.dig(:type)
68
70
 
@@ -70,26 +72,46 @@ module JsonApi::Parameters
70
72
  related_id: related_id, related_type: related_type
71
73
  ) || {}
72
74
 
73
- included_object.delete(:type)
75
+ # If at least one related object has not been found in `included` tree,
76
+ # we should not attempt to "#{relationship_key}_attributes" but
77
+ # "#{relationship_key}_ids" instead.
78
+ with_inclusion = with_inclusion ? !included_object.empty? : with_inclusion
79
+
80
+ if with_inclusion
81
+ included_object.delete(:type)
82
+ included_object[:attributes].merge(id: related_id)
83
+ else
84
+ relationship_value.dig(:id)
85
+ end
86
+ end
74
87
 
75
- included_object[:attributes].merge(id: related_id)
88
+ # We may have smells in our value array as `with_inclusion` may have been changed at some point
89
+ # but not in the beginning.
90
+ # Because of that we should clear it and make sure the results are unified (e.g. array of ids)
91
+ unless with_inclusion
92
+ vals.map do |val|
93
+ val.dig(:attributes, :id) if val.is_a?(Hash)
94
+ end
76
95
  end
77
96
 
78
- [key, val]
97
+ key = with_inclusion ? "#{pluralize(relationship_key)}_attributes".to_sym : "#{singularize(relationship_key)}_ids".to_sym
98
+
99
+ [key, vals]
79
100
  end
80
101
 
81
102
  def handle_to_one_relation(relationship_key, relationship_value)
82
103
  related_id = relationship_value.dig(:id)
83
- related_type = relationship_key.to_s
104
+ related_type = relationship_value.dig(:type)
84
105
 
85
106
  included_object = find_included_object(
86
107
  related_id: related_id, related_type: related_type
87
- )
108
+ ) || {}
88
109
 
89
- return ["#{related_type.singularize}_id".to_sym, related_id] if included_object.nil?
110
+ return ["#{singularize(relationship_key)}_id".to_sym, related_id] if included_object.empty?
90
111
 
91
112
  included_object.delete(:type)
92
- ["#{related_type.singularize}_attributes".to_sym, included_object]
113
+ included_object = included_object[:attributes].merge(id: related_id)
114
+ ["#{singularize(relationship_key)}_attributes".to_sym, included_object]
93
115
  end
94
116
 
95
117
  def find_included_object(related_id:, related_type:)
@@ -1,3 +1,5 @@
1
- module JsonApi::Parameters
2
- VERSION = '0.2.0'.freeze
1
+ module JsonApi
2
+ module Parameters
3
+ VERSION = '0.3.0'.freeze
4
+ end
3
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi_parameters
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Visuality
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-04-24 00:00:00.000000000 Z
12
+ date: 2019-05-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -235,6 +235,34 @@ dependencies:
235
235
  - - "~>"
236
236
  - !ruby/object:Gem::Version
237
237
  version: 0.3.8
238
+ - !ruby/object:Gem::Dependency
239
+ name: simplecov
240
+ requirement: !ruby/object:Gem::Requirement
241
+ requirements:
242
+ - - "~>"
243
+ - !ruby/object:Gem::Version
244
+ version: 0.16.1
245
+ type: :development
246
+ prerelease: false
247
+ version_requirements: !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - "~>"
250
+ - !ruby/object:Gem::Version
251
+ version: 0.16.1
252
+ - !ruby/object:Gem::Dependency
253
+ name: simplecov-console
254
+ requirement: !ruby/object:Gem::Requirement
255
+ requirements:
256
+ - - "~>"
257
+ - !ruby/object:Gem::Version
258
+ version: 0.4.2
259
+ type: :development
260
+ prerelease: false
261
+ version_requirements: !ruby/object:Gem::Requirement
262
+ requirements:
263
+ - - "~>"
264
+ - !ruby/object:Gem::Version
265
+ version: 0.4.2
238
266
  description: JsonApi::Parameters allows you to easily translate JSON:API compliant
239
267
  parameters to a structure expected by Rails.
240
268
  email: