jsonapi-resources 0.4.4 → 0.5.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
  SHA1:
3
- metadata.gz: a1c7d37d8e26cb718f177ebe4fd12161d43196be
4
- data.tar.gz: 944229a81d8e325bfd3fae18f39f97fb4716a346
3
+ metadata.gz: f3abcdf22a7970e7b4e51d624771006f875e857f
4
+ data.tar.gz: 26703852c97b53b7a044f545a16256024d67522a
5
5
  SHA512:
6
- metadata.gz: 750930c916c0ed48ae7fc0f1dd9b19f4d3a853f1fefd27440df9736559650e21ddec7009e94ffcccc2de6133b7b8ae0e89fa2c7f0e96587562311b50c561d3fb
7
- data.tar.gz: 1aa6132ee9712c7bdd6636090be1be3c243a823140376d6b21ede7026a77cc9c4b8a7eba6dff68b543f589650ae997f4fb13d1f360e27af3a23c45b1d5cc3bcb
6
+ metadata.gz: fa580d57a12f10e6bd3732ab0b4c6b3818b8daa81ce995110f810d05e71ef16ed4f56b934ccd518c731aca4d617621070fa61e86363acd7fdd72167ffd58fa8e
7
+ data.tar.gz: 96acb9c3f10654468c1639cd867e0658dc575318b3a452e463955ead6a64f885dbd5482a3b8a4dd803ae76b684560d839c67f507bd925b465f8f90811a43da41
data/.travis.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  language: ruby
2
+ sudo: false
2
3
  env:
3
4
  - "RAILS_VERSION=4.0"
4
5
  - "RAILS_VERSION=4.1"
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # JSONAPI::Resources [![Build Status](https://secure.travis-ci.org/cerebris/jsonapi-resources.png?branch=master)](http://travis-ci.org/cerebris/jsonapi-resources)
1
+ # JSONAPI::Resources [![Build Status](https://secure.travis-ci.org/cerebris/jsonapi-resources.png?branch=master)](http://travis-ci.org/cerebris/jsonapi-resources) [![Code Climate](https://codeclimate.com/github/cerebris/jsonapi-resources/badges/gpa.svg)](https://codeclimate.com/github/cerebris/jsonapi-resources)
2
2
 
3
3
  `JSONAPI::Resources`, or "JR", provides a framework for developing a server that complies with the
4
4
  [JSON API](http://jsonapi.org/) specification.
@@ -178,10 +178,10 @@ updating the attribute. See the [Value Formatters](#value-formatters) section fo
178
178
 
179
179
  #### Primary Key
180
180
 
181
- Resources are always represented using a key of `id`. If the underlying model does not use `id` as the primary key you
182
- can use the `primary_key` method to tell the resource which field on the model to use as the primary key. Note: this
183
- doesn't have to be the actual primary key of the model. For example you may wish to use integers internally and a
184
- different scheme publicly.
181
+ Resources are always represented using a key of `id`. The resource will interrogate the model to find the primary key.
182
+ If the underlying model does not use `id` as the primary key _and_ does not support the `primary_key` method you
183
+ must use the `primary_key` method to tell the resource which field on the model to use as the primary key. **Note:**
184
+ this _must_ be the actual primary key of the model.
185
185
 
186
186
  By default only integer values are allowed for primary key. To change this behavior you can override
187
187
  `verify_key` class method:
@@ -212,11 +212,33 @@ class AuthorResource < JSONAPI::Resource
212
212
  end
213
213
  ```
214
214
 
215
- #### Associations
215
+ #### Relationships
216
216
 
217
- Related resources need to be specified in the resource. These are declared with the `has_one` and the `has_many` methods.
217
+ Related resources need to be specified in the resource. These may be declared with the `relationship` or the `has_one`
218
+ and the `has_many` methods.
218
219
 
219
- Here's a simple example where a post has a single author and an author can have many posts:
220
+ Here's a simple example using the `relationship` method where a post has a single author and an author can have many
221
+ posts:
222
+
223
+ ```ruby
224
+ class PostResource < JSONAPI::Resource
225
+ attribute :title, :body
226
+
227
+ relationship :author, to: :one
228
+ end
229
+ ```
230
+
231
+ And the corresponding author:
232
+
233
+ ```ruby
234
+ class AuthorResource < JSONAPI::Resource
235
+ attribute :name
236
+
237
+ relationship :posts, to: :many
238
+ end
239
+ ```
240
+
241
+ And here's the equivalent resources using the `has_one` and `has_many` methods:
220
242
 
221
243
  ```ruby
222
244
  class PostResource < JSONAPI::Resource
@@ -238,14 +260,17 @@ end
238
260
 
239
261
  ##### Options
240
262
 
241
- The association methods support the following options:
263
+ The relationship methods (`relationship`, `has_one`, and `has_many`) support the following options:
242
264
 
243
265
  * `class_name` - a string specifying the underlying class for the related resource
244
266
  * `foreign_key` - the method on the resource used to fetch the related resource. Defaults to `<resource_name>_id` for has_one and `<resource_name>_ids` for has_many relationships.
245
267
  * `acts_as_set` - allows the entire set of related records to be replaced in one operation. Defaults to false if not set.
246
- * `polymorphic` - set to true to identify associations that are polymorphic.
268
+ * `polymorphic` - set to true to identify relationships that are polymorphic.
247
269
  * `relation_name` - the name of the relation to use on the model. A lambda may be provided which allows conditional selection of the relation based on the context.
248
270
 
271
+ `to_one` relationships support the additional option:
272
+ * `foreign_key_on` - defaults to `:self`. To indicate that the foreign key is on the related resource specify `:related`.
273
+
249
274
  Examples:
250
275
 
251
276
  ```ruby
@@ -286,8 +311,10 @@ class BookResource < JSONAPI::Resource
286
311
  }
287
312
  ...
288
313
  end
314
+ ```
289
315
 
290
- The polymorphic association will require the resource and controller to exist, although routing to them will cause an error.
316
+ The polymorphic relationship will require the resource and controller to exist, although routing to them will cause an
317
+ error.
291
318
 
292
319
  ```ruby
293
320
  class TaggableResource < JSONAPI::Resource; end
@@ -297,7 +324,8 @@ class TaggablesController < JSONAPI::ResourceController; end
297
324
  #### Filters
298
325
 
299
326
  Filters for locating objects of the resource type are specified in the resource definition. Single filters can be
300
- declared using the `filter` method, and multiple filters can be declared with the `filters` method on the resource class.
327
+ declared using the `filter` method, and multiple filters can be declared with the `filters` method on the resource
328
+ class.
301
329
 
302
330
  For example:
303
331
 
@@ -310,7 +338,8 @@ class ContactResource < JSONAPI::Resource
310
338
  end
311
339
  ```
312
340
 
313
- Then a request could pass in a filter for example `http://example.com/contacts?filter[name_last]=Smith` and the system will find all people where the last name exactly matches Smith.
341
+ Then a request could pass in a filter for example `http://example.com/contacts?filter[name_last]=Smith` and the system
342
+ will find all people where the last name exactly matches Smith.
314
343
 
315
344
  ##### Default Filters
316
345
 
@@ -356,7 +385,7 @@ end
356
385
  ```
357
386
 
358
387
  When you create a relationship, a method is created to fetch record(s) for that relationship. This method calls
359
- `records_for(association_name)` by default.
388
+ `records_for(relationship_name)` by default.
360
389
 
361
390
  ```ruby
362
391
  class PostResource < JSONAPI::Resource
@@ -374,13 +403,13 @@ end
374
403
 
375
404
  ```
376
405
 
377
- For example, you may want raise an error if the user is not authorized to view the associated records.
406
+ For example, you may want raise an error if the user is not authorized to view the related records.
378
407
 
379
408
  ```ruby
380
409
  class BaseResource < JSONAPI::Resource
381
- def records_for(association_name, options={})
410
+ def records_for(relationship_name, options={})
382
411
  context = options[:context]
383
- records = model.public_send(association_name)
412
+ records = model.public_send(relationship_name)
384
413
 
385
414
  unless context.current_user.can_view?(records)
386
415
  raise NotAuthorizedError
@@ -563,17 +592,17 @@ Callbacks can also be defined for `JSONAPI::OperationsProcessor` events:
563
592
  - `:operation`: Any individual operation.
564
593
  - `:find_operation`: A `find_operation`.
565
594
  - `:show_operation`: A `show_operation`.
566
- - `:show_association_operation`: A `show_association_operation`.
595
+ - `:show_relationship_operation`: A `show_relationship_operation`.
567
596
  - `:show_related_resource_operation`: A `show_related_resource_operation`.
568
597
  - `:show_related_resources_operation`: A `show_related_resources_operation`.
569
598
  - `:create_resource_operation`: A `create_resource_operation`.
570
599
  - `:remove_resource_operation`: A `remove_resource_operation`.
571
600
  - `:replace_fields_operation`: A `replace_fields_operation`.
572
- - `:replace_has_one_association_operation`: A `replace_has_one_association_operation`.
573
- - `:create_has_many_association_operation`: A `create_has_many_association_operation`.
574
- - `:replace_has_many_association_operation`: A `replace_has_many_association_operation`.
575
- - `:remove_has_many_association_operation`: A `remove_has_many_association_operation`.
576
- - `:remove_has_one_association_operation`: A `remove_has_one_association_operation`.
601
+ - `:replace_has_one_relationship_operation`: A `replace_has_one_relationship_operation`.
602
+ - `:create_has_many_relationship_operation`: A `create_has_many_relationship_operation`.
603
+ - `:replace_has_many_relationship_operation`: A `replace_has_many_relationship_operation`.
604
+ - `:remove_has_many_relationship_operation`: A `remove_has_many_relationship_operation`.
605
+ - `:remove_has_one_relationship_operation`: A `remove_has_one_relationship_operation`.
577
606
 
578
607
  The operation callbacks have access to two meta data hashes, `@operations_meta` and `@operation_meta`, two links hashes,
579
608
  `@operations_links` and `@operation_links`, the full list of `@operations`, each individual `@operation` and the
@@ -874,7 +903,7 @@ An array of resources. Nested resources can be specified with dot notation.
874
903
  A hash of resource types and arrays of fields for each resource type.
875
904
 
876
905
  *Purpose*: determines which fields are serialized for a resource type. This encompasses both attributes and
877
- association ids in the links section for a resource. Fields are global for a resource type.
906
+ relationship ids in the links section for a resource. Fields are global for a resource type.
878
907
 
879
908
  *Example*: ```fields: { people: [:email, :comments], posts: [:title, :author], comments: [:body, :post]}```
880
909
 
@@ -903,7 +932,7 @@ JR has a couple of helper methods available to assist you with setting up routes
903
932
  ##### `jsonapi_resources`
904
933
 
905
934
  Like `resources` in `ActionDispatch`, `jsonapi_resources` provides resourceful routes mapping between HTTP verbs and URLs
906
- and controller actions. This will also setup mappings for relationship URLs for a resource's associations. For example:
935
+ and controller actions. This will also setup mappings for relationship URLs for a resource's relationships. For example:
907
936
 
908
937
  ```ruby
909
938
  Rails.application.routes.draw do
@@ -916,20 +945,20 @@ gives the following routes
916
945
 
917
946
  ```
918
947
  Prefix Verb URI Pattern Controller#Action
919
- contact_links_phone_numbers GET /contacts/:contact_id/links/phone-numbers(.:format) contacts#show_association {:association=>"phone_numbers"}
920
- POST /contacts/:contact_id/links/phone-numbers(.:format) contacts#create_association {:association=>"phone_numbers"}
921
- DELETE /contacts/:contact_id/links/phone-numbers/:keys(.:format) contacts#destroy_association {:association=>"phone_numbers"}
922
- contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:association=>"phone_numbers", :source=>"contacts"}
948
+ contact_relationships_phone_numbers GET /contacts/:contact_id/relationships/phone-numbers(.:format) contacts#show_relationship {:relationship=>"phone_numbers"}
949
+ POST /contacts/:contact_id/relationships/phone-numbers(.:format) contacts#create_relationship {:relationship=>"phone_numbers"}
950
+ DELETE /contacts/:contact_id/relationships/phone-numbers/:keys(.:format) contacts#destroy_relationship {:relationship=>"phone_numbers"}
951
+ contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:relationship=>"phone_numbers", :source=>"contacts"}
923
952
  contacts GET /contacts(.:format) contacts#index
924
953
  POST /contacts(.:format) contacts#create
925
954
  contact GET /contacts/:id(.:format) contacts#show
926
955
  PATCH /contacts/:id(.:format) contacts#update
927
956
  PUT /contacts/:id(.:format) contacts#update
928
957
  DELETE /contacts/:id(.:format) contacts#destroy
929
- phone_number_links_contact GET /phone-numbers/:phone_number_id/links/contact(.:format) phone_numbers#show_association {:association=>"contact"}
930
- PUT|PATCH /phone-numbers/:phone_number_id/links/contact(.:format) phone_numbers#update_association {:association=>"contact"}
931
- DELETE /phone-numbers/:phone_number_id/links/contact(.:format) phone_numbers#destroy_association {:association=>"contact"}
932
- phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:association=>"contact", :source=>"phone_numbers"}
958
+ phone_number_relationships_contact GET /phone-numbers/:phone_number_id/relationships/contact(.:format) phone_numbers#show_relationship {:relationship=>"contact"}
959
+ PUT|PATCH /phone-numbers/:phone_number_id/relationships/contact(.:format) phone_numbers#update_relationship {:relationship=>"contact"}
960
+ DELETE /phone-numbers/:phone_number_id/relationships/contact(.:format) phone_numbers#destroy_relationship {:relationship=>"contact"}
961
+ phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:relationship=>"contact", :source=>"phone_numbers"}
933
962
  phone_numbers GET /phone-numbers(.:format) phone_numbers#index
934
963
  POST /phone-numbers(.:format) phone_numbers#create
935
964
  phone_number GET /phone-numbers/:id(.:format) phone_numbers#show
@@ -994,9 +1023,9 @@ end
994
1023
  Gives the following routes:
995
1024
 
996
1025
  ```
997
- contact_links_phone_numbers GET /contacts/:contact_id/links/phone-numbers(.:format) contacts#show_association {:association=>"phone_numbers"}
998
- POST /contacts/:contact_id/links/phone-numbers(.:format) contacts#create_association {:association=>"phone_numbers"}
999
- DELETE /contacts/:contact_id/links/phone-numbers/:keys(.:format) contacts#destroy_association {:association=>"phone_numbers"}
1026
+ contact_relationships_phone_numbers GET /contacts/:contact_id/relationships/phone-numbers(.:format) contacts#show_relationship {:relationship=>"phone_numbers"}
1027
+ POST /contacts/:contact_id/relationships/phone-numbers(.:format) contacts#create_relationship {:relationship=>"phone_numbers"}
1028
+ DELETE /contacts/:contact_id/relationships/phone-numbers/:keys(.:format) contacts#destroy_relationship {:relationship=>"phone_numbers"}
1000
1029
  contacts GET /contacts(.:format) contacts#index
1001
1030
  POST /contacts(.:format) contacts#create
1002
1031
  contact GET /contacts/:id(.:format) contacts#show
@@ -1006,7 +1035,7 @@ contact_links_phone_numbers GET /contacts/:contact_id/links/phone-numbers(.:f
1006
1035
 
1007
1036
  ```
1008
1037
 
1009
- The new routes allow you to show, create and destroy the associations between resources.
1038
+ The new routes allow you to show, create and destroy the relationships between resources.
1010
1039
 
1011
1040
  ###### `jsonapi_related_resources`
1012
1041
 
@@ -1025,7 +1054,7 @@ gives the following routes:
1025
1054
 
1026
1055
  ```
1027
1056
  Prefix Verb URI Pattern Controller#Action
1028
- contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:association=>"phone_numbers", :source=>"contacts"}
1057
+ contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:relationship=>"phone_numbers", :source=>"contacts"}
1029
1058
  contacts GET /contacts(.:format) contacts#index
1030
1059
  POST /contacts(.:format) contacts#create
1031
1060
  contact GET /contacts/:id(.:format) contacts#show
@@ -1053,7 +1082,7 @@ gives the following routes:
1053
1082
 
1054
1083
  ```
1055
1084
  Prefix Verb URI Pattern Controller#Action
1056
- phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:association=>"contact", :source=>"phone_numbers"}
1085
+ phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:relationship=>"contact", :source=>"phone_numbers"}
1057
1086
  phone_numbers GET /phone-numbers(.:format) phone_numbers#index
1058
1087
  POST /phone-numbers(.:format) phone_numbers#create
1059
1088
  phone_number GET /phone-numbers/:id(.:format) phone_numbers#show
@@ -1248,6 +1277,11 @@ JSONAPI.configure do |config|
1248
1277
  # catch this error and render a 403 status code, you should add
1249
1278
  # the `Pundit::NotAuthorizedError` to the `exception_class_whitelist`.
1250
1279
  config.exception_class_whitelist = []
1280
+
1281
+ # Resource Linkage
1282
+ # Controls the serialization of resource linkage for non compound documents
1283
+ # NOTE: always_include_has_many_linkage_data is not currently implemented
1284
+ config.always_include_has_one_linkage_data = false
1251
1285
  end
1252
1286
  ```
1253
1287
 
@@ -15,8 +15,9 @@ require 'jsonapi/error_codes'
15
15
  require 'jsonapi/request'
16
16
  require 'jsonapi/operations_processor'
17
17
  require 'jsonapi/active_record_operations_processor'
18
- require 'jsonapi/association'
18
+ require 'jsonapi/relationship'
19
19
  require 'jsonapi/include_directives'
20
20
  require 'jsonapi/operation_result'
21
21
  require 'jsonapi/operation_results'
22
22
  require 'jsonapi/callbacks'
23
+ require 'jsonapi/link_builder'
@@ -5,7 +5,7 @@ module JSONAPI
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- before_filter :ensure_correct_media_type, only: [:create, :update, :create_association, :update_association]
8
+ before_filter :ensure_correct_media_type, only: [:create, :update, :create_relationship, :update_relationship]
9
9
  append_before_filter :setup_request
10
10
  after_filter :setup_response
11
11
  end
@@ -18,7 +18,7 @@ module JSONAPI
18
18
  process_request_operations
19
19
  end
20
20
 
21
- def show_association
21
+ def show_relationship
22
22
  process_request_operations
23
23
  end
24
24
 
@@ -26,11 +26,11 @@ module JSONAPI
26
26
  process_request_operations
27
27
  end
28
28
 
29
- def create_association
29
+ def create_relationship
30
30
  process_request_operations
31
31
  end
32
32
 
33
- def update_association
33
+ def update_relationship
34
34
  process_request_operations
35
35
  end
36
36
 
@@ -42,7 +42,7 @@ module JSONAPI
42
42
  process_request_operations
43
43
  end
44
44
 
45
- def destroy_association
45
+ def destroy_relationship
46
46
  process_request_operations
47
47
  end
48
48
 
@@ -17,7 +17,9 @@ module JSONAPI
17
17
  :top_level_links_include_pagination,
18
18
  :top_level_meta_include_record_count,
19
19
  :top_level_meta_record_count_key,
20
- :exception_class_whitelist
20
+ :exception_class_whitelist,
21
+ :always_include_to_one_linkage_data,
22
+ :always_include_to_many_linkage_data
21
23
 
22
24
  def initialize
23
25
  #:underscored_key, :camelized_key, :dasherized_key, or custom
@@ -54,6 +56,12 @@ module JSONAPI
54
56
  # catch this error and render a 403 status code, you should add
55
57
  # the `Pundit::NotAuthorizedError` to the `exception_class_whitelist`.
56
58
  self.exception_class_whitelist = []
59
+
60
+ # Resource Linkage
61
+ # Controls the serialization of resource linkage for non compound documents
62
+ # NOTE: always_include_to_many_linkage_data is not currently implemented
63
+ self.always_include_to_one_linkage_data = false
64
+ self.always_include_to_many_linkage_data = false
57
65
  end
58
66
 
59
67
  def json_key_format=(format)
@@ -88,6 +96,10 @@ module JSONAPI
88
96
  attr_writer :top_level_meta_record_count_key
89
97
 
90
98
  attr_writer :exception_class_whitelist
99
+
100
+ attr_writer :always_include_to_one_linkage_data
101
+
102
+ attr_writer :always_include_to_many_linkage_data
91
103
  end
92
104
 
93
105
  class << self
data/lib/jsonapi/error.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module JSONAPI
2
2
  class Error
3
- attr_accessor :title, :detail, :id, :href, :code, :path, :links, :status
3
+ attr_accessor :title, :detail, :id, :href, :code, :source, :links, :status
4
4
 
5
5
  def initialize(options = {})
6
6
  @title = options[:title]
@@ -12,7 +12,7 @@ module JSONAPI
12
12
  else
13
13
  options[:code]
14
14
  end
15
- @path = options[:path]
15
+ @source = options[:source]
16
16
  @links = options[:links]
17
17
  @status = options[:status]
18
18
  end
@@ -73,12 +73,12 @@ module JSONAPI
73
73
  end
74
74
  end
75
75
 
76
- class HasManySetReplacementForbidden < Error
76
+ class ToManySetReplacementForbidden < Error
77
77
  def errors
78
78
  [JSONAPI::Error.new(code: JSONAPI::FORBIDDEN,
79
79
  status: :forbidden,
80
80
  title: 'Complete replacement forbidden',
81
- detail: 'Complete replacement forbidden for this association')]
81
+ detail: 'Complete replacement forbidden for this relationship')]
82
82
  end
83
83
  end
84
84
 
@@ -188,17 +188,17 @@ module JSONAPI
188
188
  end
189
189
 
190
190
  class InvalidInclude < Error
191
- attr_accessor :association, :resource
192
- def initialize(resource, association)
191
+ attr_accessor :relationship, :resource
192
+ def initialize(resource, relationship)
193
193
  @resource = resource
194
- @association = association
194
+ @relationship = relationship
195
195
  end
196
196
 
197
197
  def errors
198
198
  [JSONAPI::Error.new(code: JSONAPI::INVALID_INCLUDE,
199
199
  status: :bad_request,
200
200
  title: 'Invalid field',
201
- detail: "#{association} is not a valid association of #{resource}")]
201
+ detail: "#{relationship} is not a valid relationship of #{resource}")]
202
202
  end
203
203
  end
204
204
 
@@ -294,9 +294,11 @@ module JSONAPI
294
294
  end
295
295
 
296
296
  class ValidationErrors < Error
297
- attr_accessor :messages
298
- def initialize(messages)
299
- @messages = messages
297
+ attr_reader :error_messages, :resource_relationships
298
+
299
+ def initialize(resource)
300
+ @error_messages = resource.model.errors.messages
301
+ @resource_relationships = resource.class._relationships.keys
300
302
  @key_formatter = JSONAPI.configuration.key_formatter
301
303
  end
302
304
 
@@ -305,16 +307,26 @@ module JSONAPI
305
307
  end
306
308
 
307
309
  def errors
308
- messages.inject([]) do |arr, element|
309
- arr.concat(
310
- element[1].map do |message|
311
- JSONAPI::Error.new(code: JSONAPI::VALIDATION_ERROR,
312
- status: :unprocessable_entity,
313
- title: "#{format_key(element[0])} - #{message}",
314
- detail: message,
315
- path: "/#{element[0]}")
316
- end
317
- )
310
+ error_messages.flat_map do |attr_key, messages|
311
+ messages.map { |message| json_api_error(attr_key, message) }
312
+ end
313
+ end
314
+
315
+ private
316
+
317
+ def json_api_error(attr_key, message)
318
+ JSONAPI::Error.new(code: JSONAPI::VALIDATION_ERROR,
319
+ status: :unprocessable_entity,
320
+ title: "#{format_key(attr_key)} - #{message}",
321
+ detail: message,
322
+ source: { pointer: pointer(attr_key) })
323
+ end
324
+
325
+ def pointer(attr_or_relationship_name)
326
+ if resource_relationships.include?(attr_or_relationship_name)
327
+ "/data/relationships/#{attr_or_relationship_name}"
328
+ else
329
+ "/data/attributes/#{attr_or_relationship_name}"
318
330
  end
319
331
  end
320
332
  end
@@ -358,7 +370,7 @@ module JSONAPI
358
370
  def initialize(page, value, msg = nil)
359
371
  @page = page
360
372
  @value = value
361
- @msg = msg.nil? ? "#{value} is not a valid value for #{page} page parameter." : msg
373
+ @msg = msg || "#{value} is not a valid value for #{page} page parameter."
362
374
  end
363
375
 
364
376
  def errors