jsonapi_mapper 0.1.3 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 47223d6620e9fc3fff6740ffc29ab2667b18e2b8
4
- data.tar.gz: a8453219e94d3fb0f412f4c64256ce8e563fb399
3
+ metadata.gz: 9883b69c0cc95639ba89dd3437199363426fb85a
4
+ data.tar.gz: a76c19f1d15ad85f037f30d3bac31f669b2774f5
5
5
  SHA512:
6
- metadata.gz: 54fe745ec69e3012480a44b5a05eb67b764727a3c19be1beb45632962dcb4cf2e1ed4329dbc13e130e6d582bdd1d69775ca029600c9ea06cc23f7e2043ce69ae
7
- data.tar.gz: 3b11530b50b1159e272e7b4d6957acef70c539a3a37390bccfb5ea5f80b2ef6217adc6e39300b02da68fbed33ab4639112458e15867a56acbf5e0730a43ade72
6
+ metadata.gz: 304d9fb7484f3a7c405afe014cfc159bc0a3c25f94983e00de6bd9264ed2aa25b724891e46707fd01931393696dcad64162226bfe693ea0194d310b67e1bf280
7
+ data.tar.gz: 7556af75805a07a6fc8acefdf303b0355d2bd1ed830169baf37695876bb1aa30be7a70c5e824d7a5f5cc624620f613a247286dfda73b29aefb3e88dcb5cb8cce
data/README.md CHANGED
@@ -146,6 +146,54 @@ See the specs directory for more examples.
146
146
  pets: {nickname: :name},
147
147
  }
148
148
  }).save_all
149
+
150
+
151
+ # If any resource in your document has errors, you can get a collection
152
+ # with pointers to the specific fields and the type and id of the resource
153
+ # that has the error.
154
+ document = {
155
+ data: [
156
+ { type: 'pets', attributes: { age: 3 } },
157
+ { type: 'pets', attributes: { age: 6 } },
158
+ ],
159
+ included: [
160
+ { type: 'pets', id: '@1', attributes: { age: 4 } }
161
+ ]
162
+ }
163
+ mapper = JsonapiMapper.doc(document,
164
+ { pets: [:nickname, country: 'uruguay'] },
165
+ { types: { pets: PetDog }, attributes: { pets: {nickname: :name} } }
166
+ )
167
+
168
+ # all_valid? triggers all validations and sets up errors.
169
+ mapper.all_valid?.should be_falsey
170
+
171
+ # Then all errors are presented like so, honoring remapped names too.
172
+ mapper.all_errors.should == {
173
+ errors: [
174
+ { status: 422,
175
+ title: "can't be blank",
176
+ detail: "can't be blank",
177
+ code: "can_t_be_blank",
178
+ meta: {type: "pets"},
179
+ source: {pointer: "/data/0/attributes/nickname"}
180
+ },
181
+ { status: 422,
182
+ title: "can't be blank",
183
+ detail: "can't be blank",
184
+ code: "can_t_be_blank",
185
+ meta: {type: "pets"},
186
+ source: {pointer: "/data/1/attributes/nickname"}
187
+ },
188
+ { status: 422,
189
+ title: "can't be blank",
190
+ detail: "can't be blank",
191
+ code: "can_t_be_blank",
192
+ meta: {type: "pets"},
193
+ source: {pointer: "/included/0/attributes/nickname"}
194
+ }
195
+ ]
196
+ }
149
197
  ```
150
198
 
151
199
  ## Development
@@ -1,3 +1,3 @@
1
1
  module JsonapiMapper
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -66,15 +66,14 @@ module JsonapiMapper
66
66
  attrs = attrs.map(&:to_sym)
67
67
  scope.symbolize_keys!
68
68
 
69
- danger = scope.keys.to_set & attrs.map{|a| renamed(type_name, a) }.to_set
69
+ danger = scope.keys.to_set & attrs.map{|a| renamed_attr(type_name, a) }.to_set
70
70
  if danger.count > 0
71
71
  raise RulesError.new("Don't let user set the scope: #{danger.to_a}")
72
72
  end
73
73
 
74
- cls = renames.fetch(:types, {})[type_name] ||
75
- type_name.to_s.singularize.camelize.constantize
74
+ cls = renamed_type(type_name)
76
75
 
77
- attrs.map{|a| renamed(type_name, a) }.each do |attr|
76
+ attrs.map{|a| renamed_attr(type_name, a) }.each do |attr|
78
77
  unless cls.new.respond_to?(attr)
79
78
  raise NoMethodError.new("undefined method #{attr} for #{cls}")
80
79
  end
@@ -103,18 +102,17 @@ module JsonapiMapper
103
102
  relationships = {}
104
103
  json.fetch(:relationships, {}).each do |name, value|
105
104
  next unless type.rule.attributes.include?(name)
106
- relationships[renamed(type.name, name)] = if value[:data].is_a?(Array)
105
+ relationships[renamed_attr(type.name, name)] = if value[:data].is_a?(Array)
107
106
  value[:data].map{|v| build_id(v) }
108
107
  else
109
108
  build_id(value[:data])
110
109
  end
111
110
  end
112
111
 
113
- if attributes_to_be_set = json[:attributes]
112
+ if new_values = json[:attributes]
114
113
  type.rule.attributes.each do |name|
115
- if value = attributes_to_be_set[name]
116
- object.send("#{renamed(type.name, name)}=", value)
117
- end
114
+ next unless new_values.has_key?(name)
115
+ object.send("#{renamed_attr(type.name, name)}=", new_values[name])
118
116
  end
119
117
  end
120
118
 
@@ -149,10 +147,25 @@ module JsonapiMapper
149
147
  .new("Couldn't find #{id.type} with id=#{id.raw}")
150
148
  end
151
149
 
152
- def renamed(type, attr)
150
+ def renamed_type(type_name)
151
+ renames.fetch(:types, {})[type_name] ||
152
+ type_name.to_s.singularize.camelize.constantize
153
+ end
154
+
155
+ def unrenamed_type(type)
156
+ type_name = type.to_s.underscore.pluralize
157
+ renames.fetch(:types, {}).find{|k,v| v == type }.try(:first) || type_name
158
+ end
159
+
160
+ def renamed_attr(type, attr)
153
161
  renames.fetch(:attributes, {}).fetch(type, {}).fetch(attr, attr)
154
162
  end
155
163
 
164
+ def unrenamed_attr(type_name, attr)
165
+ renames.fetch(:attributes, {}).fetch(type_name, {})
166
+ .find{|k,v| v == attr }.try(:first) || attr
167
+ end
168
+
156
169
  def all
157
170
  (data_mappable + included)
158
171
  end
@@ -163,6 +176,10 @@ module JsonapiMapper
163
176
  true
164
177
  end
165
178
 
179
+ def all_valid?
180
+ all.map(&:valid?).all? # This does not short-circuit, to get all errors.
181
+ end
182
+
166
183
  def collection?
167
184
  data.is_a?(Array)
168
185
  end
@@ -182,5 +199,44 @@ module JsonapiMapper
182
199
  def data_mappable
183
200
  collection? ? data : [data].compact
184
201
  end
202
+
203
+ def all_errors
204
+ errors = []
205
+
206
+ if collection?
207
+ data.each_with_index do |resource, i|
208
+ errors << serialize_errors_for("/data/#{i}", resource)
209
+ end
210
+ else
211
+ errors << serialize_errors_for("/data", data)
212
+ end
213
+
214
+ included.each_with_index do |resource, i|
215
+ errors << serialize_errors_for("/included/#{i}", resource)
216
+ end
217
+
218
+ { errors: errors.flatten.compact }
219
+ end
220
+
221
+ private
222
+
223
+ def serialize_errors_for(prefix, model)
224
+ return if model.errors.empty?
225
+ model.errors.collect do |attr, value|
226
+ type_name = unrenamed_type(model.class)
227
+ meta = { type: type_name.to_s }
228
+ meta[:id] = model.id if model.id
229
+ {
230
+ status: 422,
231
+ title: value,
232
+ detail: value,
233
+ code: value.parameterize.underscore,
234
+ meta: meta,
235
+ source: {
236
+ pointer: "#{prefix}/attributes/#{unrenamed_attr(type_name, attr)}"
237
+ }
238
+ }
239
+ end
240
+ end
185
241
  end
186
242
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi_mapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - nubis
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-30 00:00:00.000000000 Z
11
+ date: 2018-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport