jsonapi-resources 0.3.1 → 0.3.2

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: c58427d88b5c0bbe33915d8039ac02a1f6ea260b
4
- data.tar.gz: 62dcacd2190abc5bffe3a10cefe1bba9d50a56b7
3
+ metadata.gz: 5f77e572b55d7703ae7464eb2cc9d90c6d70a9c7
4
+ data.tar.gz: 0d7e83c12752c0956068b8e6087174518d27ef8d
5
5
  SHA512:
6
- metadata.gz: 5ae8e6c9e4c87a8b5848110cd2acd98f98b6a1ab202edd83b62aabd9806df7880d4345a1678b551ed054706aaae14227261f07f9dce77161e3dbf260dcf1236c
7
- data.tar.gz: 1d528f86653c12a040dbb52b1db0d0f8affbf7b11440ceb0a75e3eae17d70a219872cbbb34d7fcb7ad3d04ccd366921ba146f00023a7b0910a4e74ae5f40c86a
6
+ metadata.gz: 060bbad86c169a604f0a98f316023fa8d632fd3df406a35b37bf7c4db2d7d770b74c5172aa3270a70a04a091e5126a291f2517d586ee5a32d0f198372e353b27
7
+ data.tar.gz: 3c58a190c4d755d322c6643f00450a65308ee21c514ae1c89cd466f8e4adfa20976ab1fbd115c5dcb31d4c352ad5afae932fbf3ca0e030027cd32c75eae524f8
data/README.md CHANGED
@@ -781,7 +781,15 @@ edit_contact GET /contacts/:id/edit(.:format) contacts#edit
781
781
  ```
782
782
 
783
783
  To manually add in the nested routes you can use the `jsonapi_links`, `jsonapi_related_resources` and
784
- `jsonapi_related_resource` inside the block.
784
+ `jsonapi_related_resource` inside the block. Or, you can add the default set of nested routes using the `jsonapi_relationships` method. For example:
785
+
786
+ ```ruby
787
+ Rails.application.routes.draw do
788
+ jsonapi_resources :contacts do
789
+ jsonapi_relationships
790
+ end
791
+ end
792
+ ```
785
793
 
786
794
  ###### `jsonapi_links`
787
795
 
@@ -9,7 +9,8 @@ module JSONAPI
9
9
  :allowed_request_params,
10
10
  :default_paginator,
11
11
  :default_page_size,
12
- :maximum_page_size
12
+ :maximum_page_size,
13
+ :use_text_errors
13
14
 
14
15
  def initialize
15
16
  #:underscored_key, :camelized_key, :dasherized_key, or custom
@@ -25,6 +26,7 @@ module JSONAPI
25
26
 
26
27
  self.default_page_size = 10
27
28
  self.maximum_page_size = 20
29
+ self.use_text_errors = false
28
30
  end
29
31
 
30
32
  def json_key_format=(format)
@@ -52,6 +54,10 @@ module JSONAPI
52
54
  def maximum_page_size=(maximum_page_size)
53
55
  @maximum_page_size = maximum_page_size
54
56
  end
57
+
58
+ def use_text_errors=(use_text_errors)
59
+ @use_text_errors = use_text_errors
60
+ end
55
61
  end
56
62
 
57
63
  class << self
@@ -8,10 +8,14 @@ module JSONAPI
8
8
  @detail = options[:detail]
9
9
  @id = options[:id]
10
10
  @href = options[:href]
11
- @code = options[:code]
11
+ @code = if JSONAPI.configuration.use_text_errors
12
+ TEXT_ERRORS[options[:code]]
13
+ else
14
+ options[:code]
15
+ end
12
16
  @path = options[:path]
13
17
  @links = options[:links]
14
18
  @status = options[:status]
15
19
  end
16
20
  end
17
- end
21
+ end
@@ -23,4 +23,30 @@ module JSONAPI
23
23
  RECORD_NOT_FOUND = 404
24
24
  UNSUPPORTED_MEDIA_TYPE = 415
25
25
  LOCKED = 423
26
+
27
+ TEXT_ERRORS =
28
+ { VALIDATION_ERROR => 'VALIDATION_ERROR',
29
+ INVALID_RESOURCE => 'INVALID_RESOURCE',
30
+ FILTER_NOT_ALLOWED => 'FILTER_NOT_ALLOWED',
31
+ INVALID_FIELD_VALUE => 'INVALID_FIELD_VALUE',
32
+ INVALID_FIELD => 'INVALID_FIELD',
33
+ PARAM_NOT_ALLOWED => 'PARAM_NOT_ALLOWED',
34
+ PARAM_MISSING => 'PARAM_MISSING',
35
+ INVALID_FILTER_VALUE => 'INVALID_FILTER_VALUE',
36
+ COUNT_MISMATCH => 'COUNT_MISMATCH',
37
+ KEY_ORDER_MISMATCH => 'KEY_ORDER_MISMATCH',
38
+ KEY_NOT_INCLUDED_IN_URL => 'KEY_NOT_INCLUDED_IN_URL',
39
+ INVALID_INCLUDE => 'INVALID_INCLUDE',
40
+ RELATION_EXISTS => 'RELATION_EXISTS',
41
+ INVALID_SORT_CRITERIA => 'INVALID_SORT_CRITERIA',
42
+ INVALID_LINKS_OBJECT => 'INVALID_LINKS_OBJECT',
43
+ TYPE_MISMATCH => 'TYPE_MISMATCH',
44
+ INVALID_PAGE_OBJECT => 'INVALID_PAGE_OBJECT',
45
+ INVALID_PAGE_VALUE => 'INVALID_PAGE_VALUE',
46
+ INVALID_SORT_FORMAT => 'INVALID_SORT_FORMAT',
47
+ INVALID_FIELD_FORMAT => 'INVALID_FIELD_FORMAT',
48
+ FORBIDDEN => 'FORBIDDEN',
49
+ RECORD_NOT_FOUND => 'RECORD_NOT_FOUND',
50
+ UNSUPPORTED_MEDIA_TYPE => 'UNSUPPORTED_MEDIA_TYPE',
51
+ LOCKED => 'LOCKED' }
26
52
  end
@@ -233,7 +233,7 @@ module JSONAPI
233
233
  end
234
234
 
235
235
  {
236
- type: raw['type'],
236
+ type: unformat_key(raw['type']).to_s,
237
237
  id: raw['id']
238
238
  }
239
239
  end
@@ -281,12 +281,12 @@ module JSONAPI
281
281
  # Since we do not yet support polymorphic associations we will raise an error if the type does not match the
282
282
  # association's type.
283
283
  # ToDo: Support Polymorphic associations
284
- if links_object[:type] && (links_object[:type] != association.type.to_s)
284
+ if links_object[:type] && (links_object[:type].to_s != association.type.to_s)
285
285
  raise JSONAPI::Exceptions::TypeMismatch.new(links_object[:type])
286
286
  end
287
287
 
288
288
  unless links_object[:id].nil?
289
- association_resource = Resource.resource_for(@resource_klass.module_path + links_object[:type])
289
+ association_resource = Resource.resource_for(@resource_klass.module_path + unformat_key(links_object[:type]).to_s)
290
290
  checked_has_one_associations[param] = association_resource.verify_key(links_object[:id], @context)
291
291
  else
292
292
  checked_has_one_associations[param] = nil
@@ -309,12 +309,12 @@ module JSONAPI
309
309
  if links_object.length == 0
310
310
  checked_has_many_associations[param] = []
311
311
  else
312
- if links_object.length > 1 || !links_object.has_key?(association.type.to_s)
312
+ if links_object.length > 1 || !links_object.has_key?(format_key(association.type))
313
313
  raise JSONAPI::Exceptions::TypeMismatch.new(links_object[:type])
314
314
  end
315
315
 
316
316
  links_object.each_pair do |type, keys|
317
- association_resource = Resource.resource_for(@resource_klass.module_path + type)
317
+ association_resource = Resource.resource_for(@resource_klass.module_path + unformat_key(type).to_s)
318
318
  checked_has_many_associations[param] = association_resource.verify_keys(keys, @context)
319
319
  end
320
320
  end
@@ -400,7 +400,7 @@ module JSONAPI
400
400
  end
401
401
 
402
402
  type = data[:type]
403
- if type.nil? || type != @resource_klass._type.to_s
403
+ if type.nil? || type != format_key(@resource_klass._type).to_s
404
404
  raise JSONAPI::Exceptions::ParameterMissing.new(:type)
405
405
  end
406
406
 
@@ -114,23 +114,17 @@ module JSONAPI
114
114
 
115
115
  resource = source
116
116
  id = resource.id
117
- # ToDo: See if this is actually needed
118
- # if already_serialized?(@primary_class_name, id)
119
- # set_primary(@primary_class_name, id)
120
- # end
121
-
122
117
  add_included_object(@primary_class_name, id, object_hash(source, requested_associations), true)
123
118
  end
124
119
  end
125
120
 
126
- # Returns a serialized hash for the source model, with
121
+ # Returns a serialized hash for the source model
127
122
  def object_hash(source, requested_associations)
128
123
  obj_hash = attribute_hash(source)
129
124
  links = links_hash(source, requested_associations)
130
125
 
131
- # ToDo: Do we format these required keys
132
- obj_hash[format_key('type')] = format_value(source.class._type.to_s, :default, source)
133
- obj_hash[format_key('id')] ||= format_value(source.id, :id, source)
126
+ obj_hash['type'] = format_key(source.class._type.to_s)
127
+ obj_hash['id'] ||= format_value(source.id, :id, source)
134
128
  obj_hash.merge!({links: links}) unless links.empty?
135
129
  return obj_hash
136
130
  end
@@ -250,7 +244,7 @@ module JSONAPI
250
244
  linkage = {}
251
245
  linkage_id = foreign_key_value(source, association)
252
246
  if linkage_id
253
- linkage[:type] = format_route(association.type)
247
+ linkage[:type] = format_key(association.type)
254
248
  linkage[:id] = linkage_id
255
249
  else
256
250
  linkage = nil
@@ -262,7 +256,7 @@ module JSONAPI
262
256
  linkage = []
263
257
  linkage_ids = foreign_key_value(source, association)
264
258
  linkage_ids.each do |linkage_id|
265
- linkage.append({type: format_route(association.type), id: linkage_id})
259
+ linkage.append({type: format_key(association.type), id: linkage_id})
266
260
  end
267
261
  linkage
268
262
  end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Resources
3
- VERSION = "0.3.1"
3
+ VERSION = "0.3.2"
4
4
  end
5
5
  end
@@ -18,59 +18,58 @@ module ActionDispatch
18
18
  end
19
19
 
20
20
  def jsonapi_resource(*resources, &block)
21
- resource_type = resources.first
22
- res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(resources.first))
21
+ @resource_type = resources.first
22
+ res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
23
23
 
24
24
  options = resources.extract_options!.dup
25
- options[:controller] ||= resource_type
25
+ options[:controller] ||= @resource_type
26
26
  options.merge!(res.routing_resource_options)
27
- options[:path] = format_route(resource_type)
27
+ options[:path] = format_route(@resource_type)
28
28
 
29
- resource resource_type, options do
30
- @scope[:jsonapi_resource] = resource_type
29
+ resource @resource_type, options do
30
+ @scope[:jsonapi_resource] = @resource_type
31
31
 
32
32
  if block_given?
33
33
  yield
34
34
  else
35
- res._associations.each do |association_name, association|
36
- if association.is_a?(JSONAPI::Association::HasMany)
37
- jsonapi_links(association_name)
38
- else
39
- jsonapi_link(association_name)
40
- end
41
- end
35
+ jsonapi_relationships
36
+ end
37
+ end
38
+ end
39
+
40
+ def jsonapi_relationships
41
+ res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
42
+ res._associations.each do |association_name, association|
43
+ if association.is_a?(JSONAPI::Association::HasMany)
44
+ jsonapi_links(association_name)
45
+ jsonapi_related_resources(association_name)
46
+ else
47
+ jsonapi_link(association_name)
48
+ jsonapi_related_resource(association_name)
42
49
  end
43
50
  end
44
51
  end
45
52
 
46
53
  def jsonapi_resources(*resources, &block)
47
- resource_type = resources.first
48
- res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(resources.first))
54
+ @resource_type = resources.first
55
+ res = JSONAPI::Resource.resource_for(resource_type_with_module_prefix(@resource_type))
49
56
 
50
57
  options = resources.extract_options!.dup
51
- options[:controller] ||= resource_type
58
+ options[:controller] ||= @resource_type
52
59
  options.merge!(res.routing_resource_options)
53
60
 
54
61
  # Route using the primary_key. Can be overridden using routing_resource_options
55
62
  options[:param] ||= res._primary_key
56
63
 
57
- options[:path] = format_route(resource_type)
64
+ options[:path] = format_route(@resource_type)
58
65
 
59
- resources resource_type, options do
60
- @scope[:jsonapi_resource] = resource_type
66
+ resources @resource_type, options do
67
+ @scope[:jsonapi_resource] = @resource_type
61
68
 
62
69
  if block_given?
63
70
  yield
64
71
  else
65
- res._associations.each do |association_name, association|
66
- if association.is_a?(JSONAPI::Association::HasMany)
67
- jsonapi_links(association_name)
68
- jsonapi_related_resources(association_name)
69
- else
70
- jsonapi_link(association_name)
71
- jsonapi_related_resource(association_name)
72
- end
73
- end
72
+ jsonapi_relationships
74
73
  end
75
74
  end
76
75
  end
@@ -4,6 +4,10 @@ def set_content_type_header!
4
4
  @request.headers['Content-Type'] = JSONAPI::MEDIA_TYPE
5
5
  end
6
6
 
7
+ class ConfigControllerTest < ActionController::TestCase
8
+
9
+ end
10
+
7
11
  class PostsControllerTest < ActionController::TestCase
8
12
  def test_index
9
13
  get :index
@@ -1388,6 +1392,14 @@ class ExpenseEntriesControllerTest < ActionController::TestCase
1388
1392
  JSONAPI.configuration.json_key_format = :camelized_key
1389
1393
  end
1390
1394
 
1395
+ def test_text_error
1396
+ JSONAPI.configuration.use_text_errors = true
1397
+ get :index, {sort: 'not_in_record'}
1398
+ assert_response 400
1399
+ assert_equal 'INVALID_SORT_FORMAT', json_response['errors'][0]['code']
1400
+ JSONAPI.configuration.use_text_errors = false
1401
+ end
1402
+
1391
1403
  def test_expense_entries_index
1392
1404
  get :index
1393
1405
  assert_response :success
@@ -1636,6 +1648,28 @@ class PeopleControllerTest < ActionController::TestCase
1636
1648
  assert_response :success
1637
1649
  end
1638
1650
 
1651
+ def test_update_link_with_dasherized_type
1652
+ JSONAPI.configuration.json_key_format = :dasherized_key
1653
+ set_content_type_header!
1654
+ put :update,
1655
+ {
1656
+ id: 3,
1657
+ data: {
1658
+ id: '3',
1659
+ type: 'people',
1660
+ links: {
1661
+ 'hair-cut' => {
1662
+ linkage: {
1663
+ type: 'hair-cuts',
1664
+ id: '1'
1665
+ }
1666
+ }
1667
+ }
1668
+ }
1669
+ }
1670
+ assert_response :success
1671
+ end
1672
+
1639
1673
  def test_create_validations_missing_attribute
1640
1674
  set_content_type_header!
1641
1675
  post :create,
@@ -1693,37 +1727,46 @@ class PeopleControllerTest < ActionController::TestCase
1693
1727
  end
1694
1728
 
1695
1729
  def test_get_related_resource
1730
+ JSONAPI.configuration.json_key_format = :dasherized_key
1731
+ JSONAPI.configuration.route_format = :underscored_key
1696
1732
  get :get_related_resource, {post_id: '2', association: 'author', :source=>'posts'}
1697
1733
  assert_response :success
1698
- assert_hash_equals json_response,
1699
- {
1700
- data: {
1701
- id: '1',
1702
- type: 'people',
1703
- name: 'Joe Author',
1704
- email: 'joe@xyz.fake',
1705
- dateJoined: '2013-08-07 16:25:00 -0400',
1706
- links: {
1707
- self: 'http://test.host/people/1',
1708
- comments: {
1709
- self: 'http://test.host/people/1/links/comments',
1710
- related: 'http://test.host/people/1/comments'
1711
- },
1712
- posts: {
1713
- self: 'http://test.host/people/1/links/posts',
1714
- related: 'http://test.host/people/1/posts'
1715
- },
1716
- preferences: {
1717
- self: 'http://test.host/people/1/links/preferences',
1718
- related: 'http://test.host/people/1/preferences',
1719
- linkage: {
1720
- type: 'preferences',
1721
- id: '1'
1722
- }
1723
- }
1724
- }
1725
- }
1726
- }
1734
+ assert_hash_equals(
1735
+ {
1736
+ data: {
1737
+ id: '1',
1738
+ type: 'people',
1739
+ name: 'Joe Author',
1740
+ email: 'joe@xyz.fake',
1741
+ "date-joined" => '2013-08-07 16:25:00 -0400',
1742
+ links: {
1743
+ self: 'http://test.host/people/1',
1744
+ comments: {
1745
+ self: 'http://test.host/people/1/links/comments',
1746
+ related: 'http://test.host/people/1/comments'
1747
+ },
1748
+ posts: {
1749
+ self: 'http://test.host/people/1/links/posts',
1750
+ related: 'http://test.host/people/1/posts'
1751
+ },
1752
+ preferences: {
1753
+ self: 'http://test.host/people/1/links/preferences',
1754
+ related: 'http://test.host/people/1/preferences',
1755
+ linkage: {
1756
+ type: 'preferences',
1757
+ id: '1'
1758
+ }
1759
+ },
1760
+ "hair-cut" => {
1761
+ "self" => "http://test.host/people/1/links/hair_cut",
1762
+ "related" => "http://test.host/people/1/hair_cut",
1763
+ "linkage" => nil
1764
+ }
1765
+ }
1766
+ }
1767
+ },
1768
+ json_response
1769
+ )
1727
1770
  end
1728
1771
 
1729
1772
  def test_get_related_resource_nil
@@ -12,6 +12,7 @@ ActiveRecord::Schema.define do
12
12
  t.string :email
13
13
  t.datetime :date_joined
14
14
  t.belongs_to :preferences
15
+ t.integer :hair_cut_id, index: true
15
16
  t.timestamps null: false
16
17
  end
17
18
 
@@ -113,6 +114,39 @@ ActiveRecord::Schema.define do
113
114
  t.integer :author_id
114
115
  t.timestamps null: false
115
116
  end
117
+
118
+ create_table :customers, force: true do |t|
119
+ t.string :name
120
+ end
121
+
122
+ create_table :purchase_orders, force: true do |t|
123
+ t.date :order_date
124
+ t.date :requested_delivery_date
125
+ t.date :delivery_date
126
+ t.integer :customer_id
127
+ t.string :delivery_name
128
+ t.string :delivery_address_1
129
+ t.string :delivery_address_2
130
+ t.string :delivery_city
131
+ t.string :delivery_state
132
+ t.string :delivery_postal_code
133
+ t.float :delivery_fee
134
+ t.float :tax
135
+ t.float :total
136
+ t.timestamps null: false
137
+ end
138
+
139
+ create_table :line_items, force: true do |t|
140
+ t.integer :purchase_order_id
141
+ t.string :part_number
142
+ t.string :quantity
143
+ t.float :item_cost
144
+ t.timestamps null: false
145
+ end
146
+
147
+ create_table :hair_cuts, force: true do |t|
148
+ t.string :style
149
+ end
116
150
  end
117
151
 
118
152
  ### MODELS
@@ -121,6 +155,7 @@ class Person < ActiveRecord::Base
121
155
  has_many :comments, foreign_key: 'author_id'
122
156
  has_many :expense_entries, foreign_key: 'employee_id', dependent: :restrict_with_exception
123
157
  belongs_to :preferences
158
+ belongs_to :hair_cut
124
159
 
125
160
  ### Validations
126
161
  validates :name, presence: true
@@ -239,7 +274,15 @@ class BreedData
239
274
  def remove(id)
240
275
  @breeds.delete(id)
241
276
  end
277
+ end
278
+
279
+ class CustomerOrder < ActiveRecord::Base
280
+ end
242
281
 
282
+ class PurchaseOrder < ActiveRecord::Base
283
+ end
284
+
285
+ class LineItem < ActiveRecord::Base
243
286
  end
244
287
 
245
288
  ### PORO Data - don't do this in a production app
@@ -369,6 +412,28 @@ module Api
369
412
  class IsoCurrenciesController < JSONAPI::ResourceController
370
413
  end
371
414
  end
415
+
416
+ module V6
417
+ class CustomersController < JSONAPI::ResourceController
418
+ end
419
+
420
+ class PurchaseOrdersController < JSONAPI::ResourceController
421
+ end
422
+
423
+ class LineItemsController < JSONAPI::ResourceController
424
+ end
425
+ end
426
+
427
+ module V7
428
+ class CustomersController < JSONAPI::ResourceController
429
+ end
430
+
431
+ class PurchaseOrdersController < JSONAPI::ResourceController
432
+ end
433
+
434
+ class LineItemsController < JSONAPI::ResourceController
435
+ end
436
+ end
372
437
  end
373
438
 
374
439
  ### RESOURCES
@@ -380,6 +445,7 @@ class PersonResource < JSONAPI::Resource
380
445
  has_many :posts
381
446
 
382
447
  has_one :preferences
448
+ has_one :hair_cut
383
449
 
384
450
  filter :name
385
451
 
@@ -502,6 +568,11 @@ class PostResource < JSONAPI::Resource
502
568
  end
503
569
  end
504
570
 
571
+ class HairCutResource < JSONAPI::Resource
572
+ attribute :style
573
+ has_many :people
574
+ end
575
+
505
576
  class IsoCurrencyResource < JSONAPI::Resource
506
577
  primary_key :code
507
578
  attributes :name, :country_name, :minor_unit
@@ -644,6 +715,7 @@ module Api
644
715
  PreferencesResource = PreferencesResource.dup
645
716
  EmployeeResource = EmployeeResource.dup
646
717
  FriendResource = FriendResource.dup
718
+ HairCutResource = HairCutResource.dup
647
719
  end
648
720
  end
649
721
 
@@ -721,6 +793,48 @@ module Api
721
793
  end
722
794
  end
723
795
 
796
+ module Api
797
+ module V6
798
+ class CustomerResource < JSONAPI::Resource
799
+ attribute :name
800
+
801
+ has_many :purchase_orders
802
+ end
803
+
804
+ class PurchaseOrderResource < JSONAPI::Resource
805
+ attribute :order_date
806
+ attribute :requested_delivery_date
807
+ attribute :delivery_date
808
+ attribute :delivery_name
809
+ attribute :delivery_address_1
810
+ attribute :delivery_address_2
811
+ attribute :delivery_city
812
+ attribute :delivery_state
813
+ attribute :delivery_postal_code
814
+ attribute :delivery_fee
815
+ attribute :tax
816
+ attribute :total
817
+
818
+ has_one :customer
819
+ has_many :line_items
820
+ end
821
+
822
+ class LineItemResource < JSONAPI::Resource
823
+ attribute :part_number
824
+ attribute :quantity
825
+ attribute :item_cost
826
+
827
+ has_one :purchase_order
828
+ end
829
+ end
830
+
831
+ module V7
832
+ CustomerResource = V6::CustomerResource.dup
833
+ PurchaseOrderResource = V6::PurchaseOrderResource.dup
834
+ LineItemResource = V6::LineItemResource.dup
835
+ end
836
+ end
837
+
724
838
  warn 'start testing Name Collisions'
725
839
  # The name collisions only emmit warnings. Exceptions would change the flow of the tests
726
840
 
@@ -755,4 +869,4 @@ jupiter = Planet.create(name: 'Jupiter', description: 'A gas giant.', planet_typ
755
869
  betax = Planet.create(name: 'Beta X', description: 'Newly discovered Planet X', planet_type_id: unknown.id)
756
870
  betay = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Y', planet_type_id: unknown.id)
757
871
  betaz = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Z', planet_type_id: unknown.id)
758
- betaw = Planet.create(name: 'Beta W', description: 'Newly discovered Planet W')
872
+ betaw = Planet.create(name: 'Beta W', description: 'Newly discovered Planet W')
@@ -0,0 +1,7 @@
1
+ xyz_corp:
2
+ id: 1
3
+ name: XYZ Corporation
4
+
5
+ abc_corp:
6
+ id: 2
7
+ name: ABC Corporation
@@ -0,0 +1,3 @@
1
+ mohawk:
2
+ id: 1
3
+ style: mohawk
@@ -0,0 +1,11 @@
1
+ po_1_li_1:
2
+ purchase_order_id: 1
3
+ part_number: 556324
4
+ quantity: 1
5
+ item_cost: 45.67
6
+
7
+ po_1_li_2:
8
+ purchase_order_id: 1
9
+ part_number: 79324231A
10
+ quantity: 3
11
+ item_cost: 19.99
@@ -0,0 +1,11 @@
1
+ po_1:
2
+ id: 1
3
+ requested_delivery_date:
4
+ delivery_date: nil
5
+ customer_id: 1
6
+
7
+ po_2:
8
+ id: 2
9
+ requested_delivery_date:
10
+ delivery_date: nil
11
+ customer_id: 1
@@ -5,6 +5,7 @@ class RequestTest < ActionDispatch::IntegrationTest
5
5
 
6
6
  def setup
7
7
  JSONAPI.configuration.json_key_format = :underscored_key
8
+ JSONAPI.configuration.route_format = :underscored_route
8
9
  end
9
10
 
10
11
  def after_teardown
@@ -451,4 +452,116 @@ class RequestTest < ActionDispatch::IntegrationTest
451
452
  })
452
453
  end
453
454
 
455
+ def test_flow_self_formatted_route_1
456
+ JSONAPI.configuration.route_format = :dasherized_route
457
+ JSONAPI.configuration.json_key_format = :dasherized_key
458
+ get '/api/v6/purchase-orders'
459
+ assert_equal 200, status
460
+ po_1 = json_response['data'][0]
461
+ assert_equal 'purchase-orders', json_response['data'][0]['type']
462
+
463
+ get po_1['links']['self']
464
+ assert_equal 200, status
465
+ assert_hash_equals po_1, json_response['data']
466
+ end
467
+
468
+ def test_flow_self_formatted_route_2
469
+ JSONAPI.configuration.route_format = :underscored_route
470
+ JSONAPI.configuration.json_key_format = :dasherized_key
471
+ get '/api/v7/purchase_orders'
472
+ assert_equal 200, status
473
+ assert_equal 'purchase-orders', json_response['data'][0]['type']
474
+
475
+ po_1 = json_response['data'][0]
476
+
477
+ get po_1['links']['self']
478
+ assert_equal 200, status
479
+ assert_hash_equals po_1, json_response['data']
480
+ end
481
+
482
+ def test_flow_self_formatted_route_3
483
+ JSONAPI.configuration.route_format = :underscored_route
484
+ JSONAPI.configuration.json_key_format = :underscored_key
485
+ get '/api/v7/purchase_orders'
486
+ assert_equal 200, status
487
+ assert_equal 'purchase_orders', json_response['data'][0]['type']
488
+
489
+ po_1 = json_response['data'][0]
490
+
491
+ get po_1['links']['self']
492
+ assert_equal 200, status
493
+ assert_hash_equals po_1, json_response['data']
494
+ end
495
+
496
+ def test_post_formatted_keys
497
+ JSONAPI.configuration.route_format = :dasherized_route
498
+ JSONAPI.configuration.json_key_format = :dasherized_key
499
+ post '/api/v6/purchase-orders',
500
+ {
501
+ 'data' => {
502
+ 'delivery-name' => 'ASDFG Corp',
503
+ 'type' => 'purchase-orders'
504
+ }
505
+ }.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
506
+
507
+ assert_equal 201, status
508
+ end
509
+
510
+ def test_post_formatted_keys_different_route_key_1
511
+ JSONAPI.configuration.route_format = :dasherized_route
512
+ JSONAPI.configuration.json_key_format = :underscored_key
513
+ post '/api/v6/purchase-orders',
514
+ {
515
+ 'data' => {
516
+ 'delivery_name' => 'ASDFG Corp',
517
+ 'type' => 'purchase_orders'
518
+ }
519
+ }.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
520
+
521
+ assert_equal 201, status
522
+ end
523
+
524
+ def test_post_formatted_keys_different_route_key_2
525
+ JSONAPI.configuration.route_format = :underscored_route
526
+ JSONAPI.configuration.json_key_format = :dasherized_key
527
+ post '/api/v7/purchase_orders',
528
+ {
529
+ 'data' => {
530
+ 'delivery-name' => 'ASDFG Corp',
531
+ 'type' => 'purchase-orders'
532
+ }
533
+ }.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
534
+
535
+ assert_equal 201, status
536
+ end
537
+
538
+ def test_post_formatted_keys_wrong_format
539
+ JSONAPI.configuration.route_format = :dasherized_route
540
+ JSONAPI.configuration.json_key_format = :dasherized_key
541
+ post '/api/v6/purchase-orders',
542
+ {
543
+ 'data' => {
544
+ 'delivery_name' => 'ASDFG Corp',
545
+ 'type' => 'purchase-orders'
546
+ }
547
+ }.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
548
+
549
+ assert_equal 400, status
550
+ end
551
+
552
+ def test_patch_formatted_dasherized
553
+ JSONAPI.configuration.route_format = :dasherized_route
554
+ JSONAPI.configuration.json_key_format = :dasherized_key
555
+ patch '/api/v6/purchase-orders/1',
556
+ {
557
+ 'data' => {
558
+ 'id' => '1',
559
+ 'delivery-name' => 'ASDFG Corp',
560
+ 'type' => 'purchase-orders'
561
+ }
562
+ }.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
563
+
564
+ assert_equal 200, status
565
+ end
566
+
454
567
  end
@@ -66,7 +66,9 @@ TestApp.routes.draw do
66
66
  jsonapi_resources :people
67
67
  jsonapi_resources :comments
68
68
  jsonapi_resources :tags
69
- jsonapi_resources :posts
69
+ jsonapi_resources :posts do
70
+ jsonapi_relationships
71
+ end
70
72
  jsonapi_resources :sections
71
73
  jsonapi_resources :iso_currencies
72
74
  jsonapi_resources :expense_entries
@@ -144,6 +146,20 @@ TestApp.routes.draw do
144
146
 
145
147
  end
146
148
  JSONAPI.configuration.route_format = :underscored_route
149
+
150
+ JSONAPI.configuration.route_format = :dasherized_route
151
+ namespace :v6 do
152
+ jsonapi_resources :customers
153
+ jsonapi_resources :purchase_orders
154
+ jsonapi_resources :line_items
155
+ end
156
+ JSONAPI.configuration.route_format = :underscored_route
157
+
158
+ namespace :v7 do
159
+ jsonapi_resources :customers
160
+ jsonapi_resources :purchase_orders
161
+ jsonapi_resources :line_items
162
+ end
147
163
  end
148
164
  end
149
165
 
@@ -10,6 +10,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
10
10
  @expense_entry = ExpenseEntry.find(1)
11
11
 
12
12
  JSONAPI.configuration.json_key_format = :camelized_key
13
+ JSONAPI.configuration.route_format = :camelized_route
13
14
  end
14
15
 
15
16
  def after_teardown
@@ -130,6 +131,10 @@ class SerializerTest < ActionDispatch::IntegrationTest
130
131
  end
131
132
 
132
133
  def test_serializer_include
134
+ serialized = JSONAPI::ResourceSerializer.new(
135
+ PostResource,
136
+ include: [:author]
137
+ ).serialize_to_hash(PostResource.new(@post))
133
138
 
134
139
  assert_hash_equals(
135
140
  {
@@ -188,16 +193,26 @@ class SerializerTest < ActionDispatch::IntegrationTest
188
193
  type: 'preferences',
189
194
  id: '1'
190
195
  }
196
+ },
197
+ hairCut: {
198
+ self: "/people/1/links/hairCut",
199
+ related: "/people/1/hairCut",
200
+ linkage: nil
191
201
  }
192
202
  }
193
203
  }
194
204
  ]
195
205
  },
196
- JSONAPI::ResourceSerializer.new(PostResource, include: [:author]).serialize_to_hash(
197
- PostResource.new(@post)))
206
+ serialized
207
+ )
198
208
  end
199
209
 
200
210
  def test_serializer_key_format
211
+ serialized = JSONAPI::ResourceSerializer.new(
212
+ PostResource,
213
+ include: [:author],
214
+ key_formatter: UnderscoredKeyFormatter
215
+ ).serialize_to_hash(PostResource.new(@post))
201
216
 
202
217
  assert_hash_equals(
203
218
  {
@@ -256,14 +271,17 @@ class SerializerTest < ActionDispatch::IntegrationTest
256
271
  type: 'preferences',
257
272
  id: '1'
258
273
  }
274
+ },
275
+ hair_cut: {
276
+ self: '/people/1/links/hairCut',
277
+ related: '/people/1/hairCut',
278
+ linkage: nil
259
279
  }
260
280
  }
261
281
  }
262
282
  ]
263
283
  },
264
- JSONAPI::ResourceSerializer.new(PostResource,
265
- include: [:author],
266
- key_formatter: UnderscoredKeyFormatter).serialize_to_hash(PostResource.new(@post))
284
+ serialized
267
285
  )
268
286
  end
269
287
 
@@ -564,6 +582,10 @@ class SerializerTest < ActionDispatch::IntegrationTest
564
582
  end
565
583
 
566
584
  def test_serializer_different_foreign_key
585
+ serialized = JSONAPI::ResourceSerializer.new(
586
+ PersonResource,
587
+ include: ['comments']
588
+ ).serialize_to_hash(PersonResource.new(@fred))
567
589
 
568
590
  assert_hash_equals(
569
591
  {
@@ -591,6 +613,11 @@ class SerializerTest < ActionDispatch::IntegrationTest
591
613
  self: "/people/2/links/preferences",
592
614
  related: "/people/2/preferences",
593
615
  linkage: nil
616
+ },
617
+ hairCut: {
618
+ self: "/people/2/links/hairCut",
619
+ related: "/people/2/hairCut",
620
+ linkage: nil
594
621
  }
595
622
  }
596
623
  },
@@ -653,7 +680,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
653
680
  }
654
681
  ]
655
682
  },
656
- JSONAPI::ResourceSerializer.new(PersonResource, include: ['comments']).serialize_to_hash(PersonResource.new(@fred))
683
+ serialized
657
684
  )
658
685
  end
659
686
 
@@ -1057,26 +1084,29 @@ class SerializerTest < ActionDispatch::IntegrationTest
1057
1084
  end
1058
1085
 
1059
1086
  def test_serializer_camelized_with_value_formatters
1087
+ # JSONAPI.configuration.json_key_format = :camelized_key
1088
+ # JSONAPI.configuration.route_format = :camelized_route
1089
+
1060
1090
  assert_hash_equals(
1061
1091
  {
1062
1092
  data: {
1063
- type: 'expense_entries',
1093
+ type: 'expenseEntries',
1064
1094
  id: '1',
1065
1095
  transactionDate: '04/15/2014',
1066
1096
  cost: 12.05,
1067
1097
  links: {
1068
- self: '/expense_entries/1',
1098
+ self: '/expenseEntries/1',
1069
1099
  isoCurrency: {
1070
- self: '/expense_entries/1/links/iso_currency',
1071
- related: '/expense_entries/1/iso_currency',
1100
+ self: '/expenseEntries/1/links/isoCurrency',
1101
+ related: '/expenseEntries/1/isoCurrency',
1072
1102
  linkage: {
1073
- type: 'iso_currencies',
1103
+ type: 'isoCurrencies',
1074
1104
  id: 'USD'
1075
1105
  }
1076
1106
  },
1077
1107
  employee: {
1078
- self: '/expense_entries/1/links/employee',
1079
- related: '/expense_entries/1/employee',
1108
+ self: '/expenseEntries/1/links/employee',
1109
+ related: '/expenseEntries/1/employee',
1080
1110
  linkage: {
1081
1111
  type: 'people',
1082
1112
  id: '3'
@@ -1086,13 +1116,13 @@ class SerializerTest < ActionDispatch::IntegrationTest
1086
1116
  },
1087
1117
  included: [
1088
1118
  {
1089
- type: 'iso_currencies',
1119
+ type: 'isoCurrencies',
1090
1120
  id: 'USD',
1091
1121
  countryName: 'United States',
1092
1122
  name: 'United States Dollar',
1093
1123
  minorUnit: 'cent',
1094
1124
  links: {
1095
- self: '/iso_currencies/USD'
1125
+ self: '/isoCurrencies/USD'
1096
1126
  }
1097
1127
  },
1098
1128
  {
@@ -1108,7 +1138,7 @@ class SerializerTest < ActionDispatch::IntegrationTest
1108
1138
  ]
1109
1139
  },
1110
1140
  JSONAPI::ResourceSerializer.new(ExpenseEntryResource,
1111
- include: ['iso_currency', 'employee'],
1141
+ include: ['isoCurrency', 'employee'],
1112
1142
  fields: {people: [:id, :name, :email, :date_joined]}).serialize_to_hash(
1113
1143
  ExpenseEntryResource.new(@expense_entry))
1114
1144
  )
@@ -1128,8 +1158,8 @@ class SerializerTest < ActionDispatch::IntegrationTest
1128
1158
  links: {
1129
1159
  self: '/planets/8',
1130
1160
  planetType: {
1131
- self: '/planets/8/links/planet_type',
1132
- related: '/planets/8/planet_type',
1161
+ self: '/planets/8/links/planetType',
1162
+ related: '/planets/8/planetType',
1133
1163
  linkage: nil
1134
1164
  },
1135
1165
  tags: {
@@ -1165,10 +1195,10 @@ class SerializerTest < ActionDispatch::IntegrationTest
1165
1195
  links: {
1166
1196
  self: '/planets/7',
1167
1197
  planetType: {
1168
- self: '/planets/7/links/planet_type',
1169
- related: '/planets/7/planet_type',
1198
+ self: '/planets/7/links/planetType',
1199
+ related: '/planets/7/planetType',
1170
1200
  linkage: {
1171
- type: 'planet_types',
1201
+ type: 'planetTypes',
1172
1202
  id: '5'
1173
1203
  }
1174
1204
  },
@@ -1190,8 +1220,8 @@ class SerializerTest < ActionDispatch::IntegrationTest
1190
1220
  links: {
1191
1221
  self: '/planets/8',
1192
1222
  planetType: {
1193
- self: '/planets/8/links/planet_type',
1194
- related: '/planets/8/planet_type',
1223
+ self: '/planets/8/links/planetType',
1224
+ related: '/planets/8/planetType',
1195
1225
  linkage: nil
1196
1226
  },
1197
1227
  tags: {
@@ -1207,11 +1237,11 @@ class SerializerTest < ActionDispatch::IntegrationTest
1207
1237
  ],
1208
1238
  included: [
1209
1239
  {
1210
- type: 'planet_types',
1240
+ type: 'planetTypes',
1211
1241
  id: '5',
1212
1242
  name: 'unknown',
1213
1243
  links: {
1214
- self: '/planet_types/5'
1244
+ self: '/planetTypes/5'
1215
1245
  }
1216
1246
  }
1217
1247
  ]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-resources
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Gebhardt
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-08 00:00:00.000000000 Z
12
+ date: 2015-04-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -152,13 +152,17 @@ files:
152
152
  - test/fixtures/books.yml
153
153
  - test/fixtures/comments.yml
154
154
  - test/fixtures/comments_tags.yml
155
+ - test/fixtures/customers.yml
155
156
  - test/fixtures/expense_entries.yml
156
157
  - test/fixtures/facts.yml
158
+ - test/fixtures/hair_cuts.yml
157
159
  - test/fixtures/iso_currencies.yml
160
+ - test/fixtures/line_items.yml
158
161
  - test/fixtures/people.yml
159
162
  - test/fixtures/posts.yml
160
163
  - test/fixtures/posts_tags.yml
161
164
  - test/fixtures/preferences.yml
165
+ - test/fixtures/purchase_orders.yml
162
166
  - test/fixtures/sections.yml
163
167
  - test/fixtures/tags.yml
164
168
  - test/helpers/functional_helpers.rb
@@ -204,13 +208,17 @@ test_files:
204
208
  - test/fixtures/books.yml
205
209
  - test/fixtures/comments.yml
206
210
  - test/fixtures/comments_tags.yml
211
+ - test/fixtures/customers.yml
207
212
  - test/fixtures/expense_entries.yml
208
213
  - test/fixtures/facts.yml
214
+ - test/fixtures/hair_cuts.yml
209
215
  - test/fixtures/iso_currencies.yml
216
+ - test/fixtures/line_items.yml
210
217
  - test/fixtures/people.yml
211
218
  - test/fixtures/posts.yml
212
219
  - test/fixtures/posts_tags.yml
213
220
  - test/fixtures/preferences.yml
221
+ - test/fixtures/purchase_orders.yml
214
222
  - test/fixtures/sections.yml
215
223
  - test/fixtures/tags.yml
216
224
  - test/helpers/functional_helpers.rb