jsonapi-resources 0.3.1 → 0.3.2

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: 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