jsonapi-resources 0.6.0 → 0.6.1
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 +4 -4
- data/README.md +56 -12
- data/lib/jsonapi/exceptions.rb +1 -1
- data/lib/jsonapi/paginator.rb +1 -1
- data/lib/jsonapi/resource.rb +49 -43
- data/lib/jsonapi/resource_serializer.rb +1 -1
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/routing_ext.rb +28 -18
- data/test/controllers/controller_test.rb +72 -4
- data/test/fixtures/active_record.rb +52 -27
- data/test/fixtures/makes.yml +2 -0
- data/test/fixtures/vehicles.yml +3 -2
- data/test/fixtures/web_pages.yml +3 -0
- data/test/integration/requests/request_test.rb +13 -0
- data/test/lib/generators/jsonapi/resource_generator_test.rb +1 -1
- data/test/test_helper.rb +4 -3
- data/test/unit/jsonapi_request/jsonapi_request_test.rb +0 -1
- data/test/unit/pagination/paged_paginator_test.rb +6 -6
- data/test/unit/resource/resource_test.rb +93 -8
- data/test/unit/serializer/polymorphic_serializer_test.rb +2 -2
- data/test/unit/serializer/serializer_test.rb +135 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 885923e290e5ac1db4d49ed616f8f93b978edabe
|
|
4
|
+
data.tar.gz: f9ba1571591967f00bd09b274b2aae34b01153e0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 305b0ae0b9f37ec829b178769044957f12f90c0272b69339b930deabac8f8f34bf310539597eeb01adc911c3bb897fd9aa60b52b3b077c9d925e926fa9fca157
|
|
7
|
+
data.tar.gz: d9716961f3daeb72d56ae12b37c42960f8dcd99042f8cf6d884d67081ceebfc1ae20510eef1d682fe504e726433ce443dc5007c6cd3da0a1065c1eef708948c3
|
data/README.md
CHANGED
|
@@ -106,6 +106,50 @@ class ContactResource < BaseResource
|
|
|
106
106
|
end
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
##### Immutable Resources
|
|
110
|
+
|
|
111
|
+
Resources that are immutable should be declared as such with the `immutable` method. Immutable resources will only
|
|
112
|
+
generate routes for `index`, `show` and `show_relationship`.
|
|
113
|
+
|
|
114
|
+
###### Immutable for Readonly
|
|
115
|
+
|
|
116
|
+
Some resources are read-only and are not to be modified through the API. Declaring a resource as immutable prevents
|
|
117
|
+
creation of routes that allow modification of the resource.
|
|
118
|
+
|
|
119
|
+
###### Immutable Heterogeneous Collections
|
|
120
|
+
|
|
121
|
+
Immutable resources can be used as the basis for a heterogeneous collection. Resources in heterogeneous collections can
|
|
122
|
+
still be mutated through their own type-specific endpoints.
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
class VehicleResource < JSONAPI::Resource
|
|
126
|
+
immutable
|
|
127
|
+
|
|
128
|
+
has_one :owner
|
|
129
|
+
attributes :make, :model, :serial_number
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
class CarResource < VehicleResource
|
|
133
|
+
attributes :drive_layout
|
|
134
|
+
has_one :driver
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
class BoatResource < VehicleResource
|
|
138
|
+
attributes :length_at_water_line
|
|
139
|
+
has_one :captain
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# routes
|
|
143
|
+
jsonapi_resources :vehicles
|
|
144
|
+
jsonapi_resources :cars
|
|
145
|
+
jsonapi_resources :boats
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
In the above example vehicles are immutable. A call to `/vehicles` or `/vehicles/1` will return vehicles with types
|
|
150
|
+
of either `car` or `boat`. But calls to PUT or POST a `car` must be made to `/cars`. The rails models backing the above
|
|
151
|
+
code use Single Table Inheritance.
|
|
152
|
+
|
|
109
153
|
#### Attributes
|
|
110
154
|
|
|
111
155
|
Any of a resource's attributes that are accessible must be explicitly declared. Single attributes can be declared using
|
|
@@ -516,7 +560,7 @@ section for additional details on raising errors.
|
|
|
516
560
|
class BaseResource < JSONAPI::Resource
|
|
517
561
|
def records_for(relation_name)
|
|
518
562
|
context = options[:context]
|
|
519
|
-
records =
|
|
563
|
+
records = _model.public_send(relation_name)
|
|
520
564
|
|
|
521
565
|
unless context[:current_user].can_view?(records)
|
|
522
566
|
raise NotAuthorizedError
|
|
@@ -779,12 +823,12 @@ Callbacks can be defined for the following `JSONAPI::Resource` events:
|
|
|
779
823
|
- `:update`
|
|
780
824
|
- `:remove`
|
|
781
825
|
- `:save`
|
|
782
|
-
- `:
|
|
783
|
-
- `:
|
|
784
|
-
- `:
|
|
785
|
-
- `:
|
|
786
|
-
- `:
|
|
787
|
-
- `:
|
|
826
|
+
- `:create_to_many_link`
|
|
827
|
+
- `:replace_to_many_links`
|
|
828
|
+
- `:create_to_one_link`
|
|
829
|
+
- `:replace_to_one_link`
|
|
830
|
+
- `:remove_to_many_link`
|
|
831
|
+
- `:remove_to_one_link`
|
|
788
832
|
- `:replace_fields`
|
|
789
833
|
|
|
790
834
|
##### `JSONAPI::OperationsProcessor` Callbacks
|
|
@@ -800,11 +844,11 @@ Callbacks can also be defined for `JSONAPI::OperationsProcessor` events:
|
|
|
800
844
|
- `:create_resource_operation`: A `create_resource_operation`.
|
|
801
845
|
- `:remove_resource_operation`: A `remove_resource_operation`.
|
|
802
846
|
- `:replace_fields_operation`: A `replace_fields_operation`.
|
|
803
|
-
- `:
|
|
804
|
-
- `:
|
|
805
|
-
- `:
|
|
806
|
-
- `:
|
|
807
|
-
- `:
|
|
847
|
+
- `:replace_to_one_relationship_operation`: A `replace_to_one_relationship_operation`.
|
|
848
|
+
- `:create_to_many_relationship_operation`: A `create_to_many_relationship_operation`.
|
|
849
|
+
- `:replace_to_many_relationship_operation`: A `replace_to_many_relationship_operation`.
|
|
850
|
+
- `:remove_to_many_relationship_operation`: A `remove_to_many_relationship_operation`.
|
|
851
|
+
- `:remove_to_one_relationship_operation`: A `remove_to_one_relationship_operation`.
|
|
808
852
|
|
|
809
853
|
The operation callbacks have access to two meta data hashes, `@operations_meta` and `@operation_meta`, two links hashes,
|
|
810
854
|
`@operations_links` and `@operation_links`, the full list of `@operations`, each individual `@operation` and the
|
data/lib/jsonapi/exceptions.rb
CHANGED
|
@@ -297,7 +297,7 @@ module JSONAPI
|
|
|
297
297
|
attr_reader :error_messages, :resource_relationships
|
|
298
298
|
|
|
299
299
|
def initialize(resource)
|
|
300
|
-
@error_messages = resource.
|
|
300
|
+
@error_messages = resource._model.errors.messages
|
|
301
301
|
@resource_relationships = resource.class._relationships.keys
|
|
302
302
|
@key_formatter = JSONAPI.configuration.key_formatter
|
|
303
303
|
end
|
data/lib/jsonapi/paginator.rb
CHANGED
data/lib/jsonapi/resource.rb
CHANGED
|
@@ -7,7 +7,6 @@ module JSONAPI
|
|
|
7
7
|
@@resource_types = {}
|
|
8
8
|
|
|
9
9
|
attr_reader :context
|
|
10
|
-
attr_reader :model
|
|
11
10
|
|
|
12
11
|
define_jsonapi_resources_callbacks :create,
|
|
13
12
|
:update,
|
|
@@ -27,8 +26,12 @@ module JSONAPI
|
|
|
27
26
|
@context = context
|
|
28
27
|
end
|
|
29
28
|
|
|
29
|
+
def _model
|
|
30
|
+
@model
|
|
31
|
+
end
|
|
32
|
+
|
|
30
33
|
def id
|
|
31
|
-
|
|
34
|
+
_model.public_send(self.class._primary_key)
|
|
32
35
|
end
|
|
33
36
|
|
|
34
37
|
def is_new?
|
|
@@ -112,7 +115,7 @@ module JSONAPI
|
|
|
112
115
|
# Override this on a resource to customize how the associated records
|
|
113
116
|
# are fetched for a model. Particularly helpful for authorization.
|
|
114
117
|
def records_for(relation_name)
|
|
115
|
-
|
|
118
|
+
_model.public_send relation_name
|
|
116
119
|
end
|
|
117
120
|
|
|
118
121
|
private
|
|
@@ -169,7 +172,7 @@ module JSONAPI
|
|
|
169
172
|
# TODO: Add option to skip relations that already exist instead of returning an error?
|
|
170
173
|
relation = @model.public_send(relation_name).where(relationship.primary_key => relationship_key_value).first
|
|
171
174
|
if relation.nil?
|
|
172
|
-
@model.public_send(relation_name) << related_resource.
|
|
175
|
+
@model.public_send(relation_name) << related_resource._model
|
|
173
176
|
else
|
|
174
177
|
fail JSONAPI::Exceptions::HasManyRelationExists.new(relationship_key_value)
|
|
175
178
|
end
|
|
@@ -198,8 +201,8 @@ module JSONAPI
|
|
|
198
201
|
def _replace_polymorphic_to_one_link(relationship_type, key_value, key_type)
|
|
199
202
|
relationship = self.class._relationships[relationship_type.to_sym]
|
|
200
203
|
|
|
201
|
-
|
|
202
|
-
|
|
204
|
+
_model.public_send("#{relationship.foreign_key}=", key_value)
|
|
205
|
+
_model.public_send("#{relationship.polymorphic_type}=", key_type.to_s.classify)
|
|
203
206
|
|
|
204
207
|
@save_needed = true
|
|
205
208
|
|
|
@@ -258,6 +261,7 @@ module JSONAPI
|
|
|
258
261
|
class << self
|
|
259
262
|
def inherited(base)
|
|
260
263
|
base.abstract(false)
|
|
264
|
+
base.immutable(false)
|
|
261
265
|
base._attributes = (_attributes || {}).dup
|
|
262
266
|
base._relationships = (_relationships || {}).dup
|
|
263
267
|
base._allowed_filters = (_allowed_filters || Set.new).dup
|
|
@@ -499,7 +503,7 @@ module JSONAPI
|
|
|
499
503
|
|
|
500
504
|
resources = []
|
|
501
505
|
records.each do |model|
|
|
502
|
-
resources.push new(model, context)
|
|
506
|
+
resources.push resource_for(resource_type_for(model)).new(model, context)
|
|
503
507
|
end
|
|
504
508
|
|
|
505
509
|
resources
|
|
@@ -511,7 +515,11 @@ module JSONAPI
|
|
|
511
515
|
records = apply_includes(records, options)
|
|
512
516
|
model = records.where({_primary_key => key}).first
|
|
513
517
|
fail JSONAPI::Exceptions::RecordNotFound.new(key) if model.nil?
|
|
514
|
-
new(model, context)
|
|
518
|
+
resource_for(resource_type_for(model)).new(model, context)
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
def resource_type_for(model)
|
|
522
|
+
self.module_path + model.class.to_s.underscore
|
|
515
523
|
end
|
|
516
524
|
|
|
517
525
|
# Override this method if you want to customize the relation for
|
|
@@ -554,40 +562,28 @@ module JSONAPI
|
|
|
554
562
|
|
|
555
563
|
def verify_key(key, context = nil)
|
|
556
564
|
key_type = resource_key_type
|
|
557
|
-
verification_proc = case key_type
|
|
558
565
|
|
|
566
|
+
case key_type
|
|
559
567
|
when :integer
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
return key if key.nil?
|
|
563
|
-
Integer(key)
|
|
564
|
-
rescue
|
|
565
|
-
raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key)
|
|
566
|
-
end
|
|
567
|
-
}
|
|
568
|
+
return if key.nil?
|
|
569
|
+
Integer(key)
|
|
568
570
|
when :string
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
end
|
|
576
|
-
}
|
|
571
|
+
return if key.nil?
|
|
572
|
+
if key.to_s.include?(',')
|
|
573
|
+
raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key)
|
|
574
|
+
else
|
|
575
|
+
key
|
|
576
|
+
end
|
|
577
577
|
when :uuid
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
end
|
|
585
|
-
}
|
|
578
|
+
return if key.nil?
|
|
579
|
+
if key.to_s.match(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/)
|
|
580
|
+
key
|
|
581
|
+
else
|
|
582
|
+
raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key)
|
|
583
|
+
end
|
|
586
584
|
else
|
|
587
|
-
key_type
|
|
585
|
+
key_type.call(key, context)
|
|
588
586
|
end
|
|
589
|
-
|
|
590
|
-
verification_proc.call(key, context)
|
|
591
587
|
rescue
|
|
592
588
|
raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key)
|
|
593
589
|
end
|
|
@@ -664,6 +660,18 @@ module JSONAPI
|
|
|
664
660
|
@abstract
|
|
665
661
|
end
|
|
666
662
|
|
|
663
|
+
def immutable(val = true)
|
|
664
|
+
@immutable = val
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
def _immutable
|
|
668
|
+
@immutable
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
def mutable?
|
|
672
|
+
!@immutable
|
|
673
|
+
end
|
|
674
|
+
|
|
667
675
|
def _model_class
|
|
668
676
|
return nil if _abstract
|
|
669
677
|
|
|
@@ -678,7 +686,7 @@ module JSONAPI
|
|
|
678
686
|
end
|
|
679
687
|
|
|
680
688
|
def module_path
|
|
681
|
-
|
|
689
|
+
name =~ /::[^:]+\Z/ ? ($`.freeze.gsub('::', '/') + '/').underscore : ''
|
|
682
690
|
end
|
|
683
691
|
|
|
684
692
|
def construct_order_options(sort_params)
|
|
@@ -702,13 +710,13 @@ module JSONAPI
|
|
|
702
710
|
def check_reserved_attribute_name(name)
|
|
703
711
|
# Allow :id since it can be used to specify the format. Since it is a method on the base Resource
|
|
704
712
|
# an attribute method won't be created for it.
|
|
705
|
-
if [:type
|
|
713
|
+
if [:type].include?(name.to_sym)
|
|
706
714
|
warn "[NAME COLLISION] `#{name}` is a reserved key in #{@@resource_types[_type]}."
|
|
707
715
|
end
|
|
708
716
|
end
|
|
709
717
|
|
|
710
718
|
def check_reserved_relationship_name(name)
|
|
711
|
-
if [:id, :ids, :type, :types
|
|
719
|
+
if [:id, :ids, :type, :types].include?(name.to_sym)
|
|
712
720
|
warn "[NAME COLLISION] `#{name}` is a reserved relationship name in #{@@resource_types[_type]}."
|
|
713
721
|
end
|
|
714
722
|
end
|
|
@@ -755,7 +763,7 @@ module JSONAPI
|
|
|
755
763
|
define_method attr do |options = {}|
|
|
756
764
|
if relationship.polymorphic?
|
|
757
765
|
associated_model = public_send(associated_records_method_name)
|
|
758
|
-
resource_klass = Resource.resource_for(self.class.
|
|
766
|
+
resource_klass = Resource.resource_for(self.class.resource_type_for(associated_model)) if associated_model
|
|
759
767
|
return resource_klass.new(associated_model, @context) if resource_klass
|
|
760
768
|
else
|
|
761
769
|
resource_klass = relationship.resource_klass
|
|
@@ -808,9 +816,7 @@ module JSONAPI
|
|
|
808
816
|
end
|
|
809
817
|
|
|
810
818
|
return records.collect do |record|
|
|
811
|
-
|
|
812
|
-
resource_klass = Resource.resource_for(self.class.module_path + record.class.to_s.underscore)
|
|
813
|
-
end
|
|
819
|
+
resource_klass = Resource.resource_for(self.class.resource_type_for(record))
|
|
814
820
|
resource_klass.new(record, @context)
|
|
815
821
|
end
|
|
816
822
|
end unless method_defined?(attr)
|
|
@@ -282,7 +282,7 @@ module JSONAPI
|
|
|
282
282
|
def foreign_key_types_and_values(source, relationship)
|
|
283
283
|
if relationship.is_a?(JSONAPI::Relationship::ToMany)
|
|
284
284
|
if relationship.polymorphic?
|
|
285
|
-
source.
|
|
285
|
+
source._model.public_send(relationship.name).pluck(:type, :id).map do |type, id|
|
|
286
286
|
[type.pluralize, IdValueFormatter.format(id)]
|
|
287
287
|
end
|
|
288
288
|
else
|
data/lib/jsonapi/routing_ext.rb
CHANGED
|
@@ -80,6 +80,12 @@ module ActionDispatch
|
|
|
80
80
|
options[:except] = [:new, :edit]
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
if res._immutable
|
|
84
|
+
options[:except] << :create
|
|
85
|
+
options[:except] << :update
|
|
86
|
+
options[:except] << :destroy
|
|
87
|
+
end
|
|
88
|
+
|
|
83
89
|
resources @resource_type, options do
|
|
84
90
|
@scope[:jsonapi_resource] = @resource_type
|
|
85
91
|
|
|
@@ -117,14 +123,16 @@ module ActionDispatch
|
|
|
117
123
|
action: 'show_relationship', relationship: link_type.to_s, via: [:get]
|
|
118
124
|
end
|
|
119
125
|
|
|
120
|
-
if
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
126
|
+
if res.mutable?
|
|
127
|
+
if methods.include?(:update)
|
|
128
|
+
match "relationships/#{formatted_relationship_name}", controller: options[:controller],
|
|
129
|
+
action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
|
|
130
|
+
end
|
|
124
131
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
if methods.include?(:destroy)
|
|
133
|
+
match "relationships/#{formatted_relationship_name}", controller: options[:controller],
|
|
134
|
+
action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
|
|
135
|
+
end
|
|
128
136
|
end
|
|
129
137
|
end
|
|
130
138
|
|
|
@@ -143,19 +151,21 @@ module ActionDispatch
|
|
|
143
151
|
action: 'show_relationship', relationship: link_type.to_s, via: [:get]
|
|
144
152
|
end
|
|
145
153
|
|
|
146
|
-
if
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
154
|
+
if res.mutable?
|
|
155
|
+
if methods.include?(:create)
|
|
156
|
+
match "relationships/#{formatted_relationship_name}", controller: options[:controller],
|
|
157
|
+
action: 'create_relationship', relationship: link_type.to_s, via: [:post]
|
|
158
|
+
end
|
|
150
159
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
160
|
+
if methods.include?(:update)
|
|
161
|
+
match "relationships/#{formatted_relationship_name}", controller: options[:controller],
|
|
162
|
+
action: 'update_relationship', relationship: link_type.to_s, via: [:put, :patch]
|
|
163
|
+
end
|
|
155
164
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
if methods.include?(:destroy)
|
|
166
|
+
match "relationships/#{formatted_relationship_name}", controller: options[:controller],
|
|
167
|
+
action: 'destroy_relationship', relationship: link_type.to_s, via: [:delete]
|
|
168
|
+
end
|
|
159
169
|
end
|
|
160
170
|
end
|
|
161
171
|
|
|
@@ -3069,15 +3069,15 @@ class Api::V1::CratersControllerTest < ActionController::TestCase
|
|
|
3069
3069
|
data: [
|
|
3070
3070
|
{id:"A4D3",
|
|
3071
3071
|
type:"craters",
|
|
3072
|
-
links:{self: "http://test.host/craters/A4D3"},
|
|
3072
|
+
links:{self: "http://test.host/api/v1/craters/A4D3"},
|
|
3073
3073
|
attributes:{code: "A4D3", description: "Small crater"},
|
|
3074
|
-
relationships:{moon: {links: {self: "http://test.host/craters/A4D3/relationships/moon", related: "http://test.host/craters/A4D3/moon"}}}
|
|
3074
|
+
relationships:{moon: {links: {self: "http://test.host/api/v1/craters/A4D3/relationships/moon", related: "http://test.host/api/v1/craters/A4D3/moon"}}}
|
|
3075
3075
|
},
|
|
3076
3076
|
{id: "S56D",
|
|
3077
3077
|
type: "craters",
|
|
3078
|
-
links:{self: "http://test.host/craters/S56D"},
|
|
3078
|
+
links:{self: "http://test.host/api/v1/craters/S56D"},
|
|
3079
3079
|
attributes:{code: "S56D", description: "Very large crater"},
|
|
3080
|
-
relationships:{moon: {links: {self: "http://test.host/craters/S56D/relationships/moon", related: "http://test.host/craters/S56D/moon"}}}
|
|
3080
|
+
relationships:{moon: {links: {self: "http://test.host/api/v1/craters/S56D/relationships/moon", related: "http://test.host/api/v1/craters/S56D/moon"}}}
|
|
3081
3081
|
}
|
|
3082
3082
|
]
|
|
3083
3083
|
}
|
|
@@ -3091,3 +3091,71 @@ class Api::V1::CratersControllerTest < ActionController::TestCase
|
|
|
3091
3091
|
assert_equal "1", json_response['data']['id']
|
|
3092
3092
|
end
|
|
3093
3093
|
end
|
|
3094
|
+
|
|
3095
|
+
class CarsControllerTest < ActionController::TestCase
|
|
3096
|
+
def setup
|
|
3097
|
+
JSONAPI.configuration.json_key_format = :camelized_key
|
|
3098
|
+
end
|
|
3099
|
+
|
|
3100
|
+
def test_create_sti
|
|
3101
|
+
set_content_type_header!
|
|
3102
|
+
post :create,
|
|
3103
|
+
{
|
|
3104
|
+
data: {
|
|
3105
|
+
type: 'cars',
|
|
3106
|
+
attributes: {
|
|
3107
|
+
make: 'Toyota',
|
|
3108
|
+
model: 'Tercel',
|
|
3109
|
+
serialNumber: 'asasdsdadsa13544235',
|
|
3110
|
+
driveLayout: 'FWD'
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3115
|
+
assert_response :created
|
|
3116
|
+
assert json_response['data'].is_a?(Hash)
|
|
3117
|
+
assert_equal 'cars', json_response['data']['type']
|
|
3118
|
+
assert_equal 'Toyota', json_response['data']['attributes']['make']
|
|
3119
|
+
assert_equal 'FWD', json_response['data']['attributes']['driveLayout']
|
|
3120
|
+
end
|
|
3121
|
+
end
|
|
3122
|
+
|
|
3123
|
+
class VehiclesControllerTest < ActionController::TestCase
|
|
3124
|
+
def setup
|
|
3125
|
+
JSONAPI.configuration.json_key_format = :camelized_key
|
|
3126
|
+
end
|
|
3127
|
+
|
|
3128
|
+
def test_immutable_create_not_supported
|
|
3129
|
+
set_content_type_header!
|
|
3130
|
+
|
|
3131
|
+
assert_raises ActionController::UrlGenerationError do
|
|
3132
|
+
post :create,
|
|
3133
|
+
{
|
|
3134
|
+
data: {
|
|
3135
|
+
type: 'cars',
|
|
3136
|
+
attributes: {
|
|
3137
|
+
make: 'Toyota',
|
|
3138
|
+
model: 'Corrola',
|
|
3139
|
+
serialNumber: 'dsvffsfv',
|
|
3140
|
+
driveLayout: 'FWD'
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
end
|
|
3145
|
+
end
|
|
3146
|
+
|
|
3147
|
+
def test_immutable_update_not_supported
|
|
3148
|
+
set_content_type_header!
|
|
3149
|
+
|
|
3150
|
+
assert_raises ActionController::UrlGenerationError do
|
|
3151
|
+
patch :update,
|
|
3152
|
+
data: {
|
|
3153
|
+
id: '1',
|
|
3154
|
+
type: 'cars',
|
|
3155
|
+
attributes: {
|
|
3156
|
+
make: 'Toyota',
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
end
|
|
3160
|
+
end
|
|
3161
|
+
end
|
|
@@ -214,12 +214,34 @@ ActiveRecord::Schema.define do
|
|
|
214
214
|
create_table :vehicles, force: true do |t|
|
|
215
215
|
t.string :type
|
|
216
216
|
t.string :make
|
|
217
|
-
t.string :
|
|
217
|
+
t.string :model
|
|
218
218
|
t.string :length_at_water_line
|
|
219
219
|
t.string :drive_layout
|
|
220
220
|
t.string :serial_number
|
|
221
221
|
t.integer :person_id
|
|
222
222
|
end
|
|
223
|
+
|
|
224
|
+
create_table :makes, force: true do |t|
|
|
225
|
+
t.string :model
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# special cases - fields that look like they should be reserved names
|
|
229
|
+
create_table :hrefs, force: true do |t|
|
|
230
|
+
t.string :name
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
create_table :links, force: true do |t|
|
|
234
|
+
t.string :name
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
create_table :web_pages, force: true do |t|
|
|
238
|
+
t.string :href
|
|
239
|
+
t.string :link
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
create_table :questionables, force: true do |t|
|
|
243
|
+
end
|
|
244
|
+
# special cases
|
|
223
245
|
end
|
|
224
246
|
|
|
225
247
|
### MODELS
|
|
@@ -474,6 +496,12 @@ class Product < ActiveRecord::Base
|
|
|
474
496
|
has_one :picture, as: :imageable
|
|
475
497
|
end
|
|
476
498
|
|
|
499
|
+
class Make < ActiveRecord::Base
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
class WebPage < ActiveRecord::Base
|
|
503
|
+
end
|
|
504
|
+
|
|
477
505
|
### OperationsProcessor
|
|
478
506
|
class CountingActiveRecordOperationsProcessor < ActiveRecordOperationsProcessor
|
|
479
507
|
after_find_operation do
|
|
@@ -558,6 +586,15 @@ end
|
|
|
558
586
|
class ImageablesController < JSONAPI::ResourceController
|
|
559
587
|
end
|
|
560
588
|
|
|
589
|
+
class VehiclesController < JSONAPI::ResourceController
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
class CarsController < JSONAPI::ResourceController
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
class BoatsController < JSONAPI::ResourceController
|
|
596
|
+
end
|
|
597
|
+
|
|
561
598
|
### CONTROLLERS
|
|
562
599
|
module Api
|
|
563
600
|
module V1
|
|
@@ -701,7 +738,7 @@ class BaseResource < JSONAPI::Resource
|
|
|
701
738
|
end
|
|
702
739
|
|
|
703
740
|
class PersonResource < BaseResource
|
|
704
|
-
attributes :
|
|
741
|
+
attributes :name, :email
|
|
705
742
|
attribute :date_joined, format: :date_with_timezone
|
|
706
743
|
|
|
707
744
|
has_many :comments
|
|
@@ -727,8 +764,10 @@ class PersonResource < BaseResource
|
|
|
727
764
|
end
|
|
728
765
|
|
|
729
766
|
class VehicleResource < JSONAPI::Resource
|
|
767
|
+
immutable
|
|
768
|
+
|
|
730
769
|
has_one :person
|
|
731
|
-
attributes :make, :
|
|
770
|
+
attributes :make, :model, :serial_number
|
|
732
771
|
end
|
|
733
772
|
|
|
734
773
|
class CarResource < VehicleResource
|
|
@@ -763,12 +802,6 @@ class TagResource < JSONAPI::Resource
|
|
|
763
802
|
#has_many :planets
|
|
764
803
|
end
|
|
765
804
|
|
|
766
|
-
class SpecialTagResource < JSONAPI::Resource
|
|
767
|
-
attributes :name
|
|
768
|
-
|
|
769
|
-
has_many :posts
|
|
770
|
-
end
|
|
771
|
-
|
|
772
805
|
class SectionResource < JSONAPI::Resource
|
|
773
806
|
attributes 'name'
|
|
774
807
|
end
|
|
@@ -893,7 +926,6 @@ class FriendResource < JSONAPI::Resource
|
|
|
893
926
|
end
|
|
894
927
|
|
|
895
928
|
class BreedResource < JSONAPI::Resource
|
|
896
|
-
attribute :id, format_misspelled: :does_not_exist
|
|
897
929
|
attribute :name, format: :title
|
|
898
930
|
|
|
899
931
|
# This is unneeded, just here for testing
|
|
@@ -1003,13 +1035,22 @@ class ProductResource < JSONAPI::Resource
|
|
|
1003
1035
|
has_one :picture, always_include_linkage_data: true
|
|
1004
1036
|
|
|
1005
1037
|
def picture_id
|
|
1006
|
-
|
|
1038
|
+
_model.picture.id
|
|
1007
1039
|
end
|
|
1008
1040
|
end
|
|
1009
1041
|
|
|
1010
1042
|
class ImageableResource < JSONAPI::Resource
|
|
1011
1043
|
end
|
|
1012
1044
|
|
|
1045
|
+
class MakeResource < JSONAPI::Resource
|
|
1046
|
+
attribute :model
|
|
1047
|
+
end
|
|
1048
|
+
|
|
1049
|
+
class WebPageResource < JSONAPI::Resource
|
|
1050
|
+
attribute :href
|
|
1051
|
+
attribute :link
|
|
1052
|
+
end
|
|
1053
|
+
|
|
1013
1054
|
module Api
|
|
1014
1055
|
module V1
|
|
1015
1056
|
class WriterResource < JSONAPI::Resource
|
|
@@ -1328,22 +1369,6 @@ module MyEngine
|
|
|
1328
1369
|
end
|
|
1329
1370
|
end
|
|
1330
1371
|
|
|
1331
|
-
warn 'start testing Name Collisions'
|
|
1332
|
-
# The name collisions only emmit warnings. Exceptions would change the flow of the tests
|
|
1333
|
-
|
|
1334
|
-
class LinksResource < JSONAPI::Resource
|
|
1335
|
-
end
|
|
1336
|
-
|
|
1337
|
-
class BadlyNamedAttributesResource < JSONAPI::Resource
|
|
1338
|
-
attributes :type, :href, :links
|
|
1339
|
-
|
|
1340
|
-
has_many :links
|
|
1341
|
-
has_one :href
|
|
1342
|
-
has_one :id
|
|
1343
|
-
has_many :types
|
|
1344
|
-
end
|
|
1345
|
-
warn 'end testing Name Collisions'
|
|
1346
|
-
|
|
1347
1372
|
### PORO Data - don't do this in a production app
|
|
1348
1373
|
$breed_data = BreedData.new
|
|
1349
1374
|
$breed_data.add(Breed.new(0, 'persian'))
|
data/test/fixtures/vehicles.yml
CHANGED
|
@@ -2,15 +2,16 @@ Miata:
|
|
|
2
2
|
id: 1
|
|
3
3
|
type: Car
|
|
4
4
|
make: Mazda
|
|
5
|
-
|
|
5
|
+
model: Miata MX5
|
|
6
6
|
drive_layout: Front Engine RWD
|
|
7
7
|
serial_number: 32432adfsfdysua
|
|
8
8
|
person_id: 1
|
|
9
|
+
|
|
9
10
|
Launch20:
|
|
10
11
|
id: 2
|
|
11
12
|
type: Boat
|
|
12
13
|
make: Chris-Craft
|
|
13
|
-
|
|
14
|
+
model: Launch 20
|
|
14
15
|
length_at_water_line: 15.5ft
|
|
15
16
|
serial_number: 434253JJJSD
|
|
16
17
|
person_id: 1
|
|
@@ -910,4 +910,17 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
|
910
910
|
ensure
|
|
911
911
|
JSONAPI.configuration.allow_sort = true
|
|
912
912
|
end
|
|
913
|
+
|
|
914
|
+
def test_getting_different_resources_when_sti
|
|
915
|
+
get '/vehicles'
|
|
916
|
+
assert_equal 200, status
|
|
917
|
+
types = json_response['data'].map{|r| r['type']}.sort
|
|
918
|
+
assert_array_equals ['boats', 'cars'], types
|
|
919
|
+
end
|
|
920
|
+
|
|
921
|
+
def test_getting_resource_with_correct_type_when_sti
|
|
922
|
+
get '/vehicles/1'
|
|
923
|
+
assert_equal 200, status
|
|
924
|
+
assert_equal 'cars', json_response['data']['type']
|
|
925
|
+
end
|
|
913
926
|
end
|
data/test/test_helper.rb
CHANGED
|
@@ -39,6 +39,7 @@ class TestApp < Rails::Application
|
|
|
39
39
|
#Raise errors on unsupported parameters
|
|
40
40
|
config.action_controller.action_on_unpermitted_parameters = :raise
|
|
41
41
|
|
|
42
|
+
ActiveRecord::Schema.verbose = false
|
|
42
43
|
config.active_record.schema_format = :none
|
|
43
44
|
config.active_support.test_order = :random
|
|
44
45
|
|
|
@@ -104,7 +105,6 @@ module Pets
|
|
|
104
105
|
end
|
|
105
106
|
|
|
106
107
|
class CatResource < JSONAPI::Resource
|
|
107
|
-
attribute :id
|
|
108
108
|
attribute :name
|
|
109
109
|
attribute :breed
|
|
110
110
|
|
|
@@ -137,8 +137,9 @@ TestApp.routes.draw do
|
|
|
137
137
|
jsonapi_resources :pictures
|
|
138
138
|
jsonapi_resources :documents
|
|
139
139
|
jsonapi_resources :products
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
jsonapi_resources :vehicles
|
|
141
|
+
jsonapi_resources :cars
|
|
142
|
+
jsonapi_resources :boats
|
|
142
143
|
|
|
143
144
|
namespace :api do
|
|
144
145
|
namespace :v1 do
|
|
@@ -184,8 +184,8 @@ class PagedPaginatorTest < ActiveSupport::TestCase
|
|
|
184
184
|
assert_equal 5, links_params['first']['size']
|
|
185
185
|
assert_equal 1, links_params['first']['number']
|
|
186
186
|
|
|
187
|
-
assert_equal 5, links_params['
|
|
188
|
-
assert_equal 3, links_params['
|
|
187
|
+
assert_equal 5, links_params['prev']['size']
|
|
188
|
+
assert_equal 3, links_params['prev']['number']
|
|
189
189
|
|
|
190
190
|
assert_equal 5, links_params['next']['size']
|
|
191
191
|
assert_equal 5, links_params['next']['number']
|
|
@@ -210,8 +210,8 @@ class PagedPaginatorTest < ActiveSupport::TestCase
|
|
|
210
210
|
assert_equal 5, links_params['first']['size']
|
|
211
211
|
assert_equal 1, links_params['first']['number']
|
|
212
212
|
|
|
213
|
-
assert_equal 5, links_params['
|
|
214
|
-
assert_equal 9, links_params['
|
|
213
|
+
assert_equal 5, links_params['prev']['size']
|
|
214
|
+
assert_equal 9, links_params['prev']['number']
|
|
215
215
|
|
|
216
216
|
assert_equal 5, links_params['last']['size']
|
|
217
217
|
assert_equal 10, links_params['last']['number']
|
|
@@ -233,8 +233,8 @@ class PagedPaginatorTest < ActiveSupport::TestCase
|
|
|
233
233
|
assert_equal 5, links_params['first']['size']
|
|
234
234
|
assert_equal 1, links_params['first']['number']
|
|
235
235
|
|
|
236
|
-
assert_equal 5, links_params['
|
|
237
|
-
assert_equal 10, links_params['
|
|
236
|
+
assert_equal 5, links_params['prev']['size']
|
|
237
|
+
assert_equal 10, links_params['prev']['number']
|
|
238
238
|
|
|
239
239
|
assert_equal 5, links_params['last']['size']
|
|
240
240
|
assert_equal 10, links_params['last']['number']
|
|
@@ -16,7 +16,6 @@ class NoMatchAbstractResource < JSONAPI::Resource
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
class CatResource < JSONAPI::Resource
|
|
19
|
-
attribute :id
|
|
20
19
|
attribute :name
|
|
21
20
|
attribute :breed
|
|
22
21
|
|
|
@@ -111,7 +110,7 @@ class ResourceTest < ActiveSupport::TestCase
|
|
|
111
110
|
|
|
112
111
|
def test_find_with_customized_base_records
|
|
113
112
|
author = Person.find(1)
|
|
114
|
-
posts = ArticleResource.find([], context: author).map(&:
|
|
113
|
+
posts = ArticleResource.find([], context: author).map(&:_model)
|
|
115
114
|
|
|
116
115
|
assert(posts.include?(Post.find(1)))
|
|
117
116
|
refute(posts.include?(Post.find(3)))
|
|
@@ -123,10 +122,10 @@ class ResourceTest < ActiveSupport::TestCase
|
|
|
123
122
|
refute(preferences == nil)
|
|
124
123
|
author.update! preferences: preferences
|
|
125
124
|
author_resource = PersonResource.new(author, nil)
|
|
126
|
-
assert_equal(author_resource.preferences.
|
|
125
|
+
assert_equal(author_resource.preferences._model, preferences)
|
|
127
126
|
|
|
128
127
|
author_resource = PersonWithCustomRecordsForResource.new(author, nil)
|
|
129
|
-
assert_equal(author_resource.preferences.
|
|
128
|
+
assert_equal(author_resource.preferences._model, :records_for)
|
|
130
129
|
|
|
131
130
|
author_resource = PersonWithCustomRecordsForErrorResource.new(author, nil)
|
|
132
131
|
assert_raises PersonWithCustomRecordsForErrorResource::AuthorizationError do
|
|
@@ -165,11 +164,11 @@ class ResourceTest < ActiveSupport::TestCase
|
|
|
165
164
|
def test_find_by_key_with_customized_base_records
|
|
166
165
|
author = Person.find(1)
|
|
167
166
|
|
|
168
|
-
post = ArticleResource.find_by_key(1, context: author).
|
|
167
|
+
post = ArticleResource.find_by_key(1, context: author)._model
|
|
169
168
|
assert_equal(post, Post.find(1))
|
|
170
169
|
|
|
171
170
|
assert_raises JSONAPI::Exceptions::RecordNotFound do
|
|
172
|
-
ArticleResource.find_by_key(3, context: author).
|
|
171
|
+
ArticleResource.find_by_key(3, context: author)._model
|
|
173
172
|
end
|
|
174
173
|
end
|
|
175
174
|
|
|
@@ -221,7 +220,7 @@ class ResourceTest < ActiveSupport::TestCase
|
|
|
221
220
|
|
|
222
221
|
def test_to_many_relationship_sorts
|
|
223
222
|
post_resource = PostResource.new(Post.find(1), nil)
|
|
224
|
-
comment_ids = post_resource.comments.map{|c| c.
|
|
223
|
+
comment_ids = post_resource.comments.map{|c| c._model.id }
|
|
225
224
|
assert_equal [1,2], comment_ids
|
|
226
225
|
|
|
227
226
|
# define apply_filters method on post resource to not respect filters
|
|
@@ -233,7 +232,7 @@ class ResourceTest < ActiveSupport::TestCase
|
|
|
233
232
|
end
|
|
234
233
|
end
|
|
235
234
|
|
|
236
|
-
sorted_comment_ids = post_resource.comments(sort_criteria: [{ field: 'id', direction: :desc}]).map{|c| c.
|
|
235
|
+
sorted_comment_ids = post_resource.comments(sort_criteria: [{ field: 'id', direction: :desc}]).map{|c| c._model.id }
|
|
237
236
|
assert_equal [2,1], sorted_comment_ids
|
|
238
237
|
|
|
239
238
|
ensure
|
|
@@ -362,4 +361,90 @@ class ResourceTest < ActiveSupport::TestCase
|
|
|
362
361
|
key_type nil
|
|
363
362
|
end
|
|
364
363
|
end
|
|
364
|
+
|
|
365
|
+
def test_id_attr_deprecation
|
|
366
|
+
_out, err = capture_io do
|
|
367
|
+
eval <<-CODE
|
|
368
|
+
class ProblemResource < JSONAPI::Resource
|
|
369
|
+
attribute :id
|
|
370
|
+
end
|
|
371
|
+
CODE
|
|
372
|
+
end
|
|
373
|
+
assert_match /DEPRECATION WARNING: Id without format is no longer supported. Please remove ids from attributes, or specify a format./, err
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def test_id_attr_with_format
|
|
377
|
+
_out, err = capture_io do
|
|
378
|
+
eval <<-CODE
|
|
379
|
+
class NotProblemResource < JSONAPI::Resource
|
|
380
|
+
attribute :id, format: :string
|
|
381
|
+
end
|
|
382
|
+
CODE
|
|
383
|
+
end
|
|
384
|
+
assert_equal "", err
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def test_links_resource_warning
|
|
388
|
+
_out, err = capture_io do
|
|
389
|
+
eval "class LinksResource < JSONAPI::Resource; end"
|
|
390
|
+
end
|
|
391
|
+
assert_match /LinksResource` is a reserved resource name/, err
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def test_reserved_key_warnings
|
|
395
|
+
_out, err = capture_io do
|
|
396
|
+
eval <<-CODE
|
|
397
|
+
class BadlyNamedAttributesResource < JSONAPI::Resource
|
|
398
|
+
attributes :type
|
|
399
|
+
end
|
|
400
|
+
CODE
|
|
401
|
+
end
|
|
402
|
+
assert_match /`type` is a reserved key in ./, err
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def test_reserved_relationship_warnings
|
|
406
|
+
%w(id type).each do |key|
|
|
407
|
+
_out, err = capture_io do
|
|
408
|
+
eval <<-CODE
|
|
409
|
+
class BadlyNamedAttributesResource < JSONAPI::Resource
|
|
410
|
+
has_one :#{key}
|
|
411
|
+
end
|
|
412
|
+
CODE
|
|
413
|
+
end
|
|
414
|
+
assert_match /`#{key}` is a reserved relationship name in ./, err
|
|
415
|
+
end
|
|
416
|
+
%w(types ids).each do |key|
|
|
417
|
+
_out, err = capture_io do
|
|
418
|
+
eval <<-CODE
|
|
419
|
+
class BadlyNamedAttributesResource < JSONAPI::Resource
|
|
420
|
+
has_many :#{key}
|
|
421
|
+
end
|
|
422
|
+
CODE
|
|
423
|
+
end
|
|
424
|
+
assert_match /`#{key}` is a reserved relationship name in ./, err
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
def test_abstract_warning
|
|
429
|
+
_out, err = capture_io do
|
|
430
|
+
eval <<-CODE
|
|
431
|
+
class NoModelResource < JSONAPI::Resource
|
|
432
|
+
end
|
|
433
|
+
NoModelResource._model_class
|
|
434
|
+
CODE
|
|
435
|
+
end
|
|
436
|
+
assert_match "[MODEL NOT FOUND] Model could not be found for ResourceTest::NoModelResource. If this a base Resource declare it as abstract.\n", err
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def test_no_warning_when_abstract
|
|
440
|
+
_out, err = capture_io do
|
|
441
|
+
eval <<-CODE
|
|
442
|
+
class NoModelAbstractResource < JSONAPI::Resource
|
|
443
|
+
abstract
|
|
444
|
+
end
|
|
445
|
+
NoModelAbstractResource._model_class
|
|
446
|
+
CODE
|
|
447
|
+
end
|
|
448
|
+
assert_match "", err
|
|
449
|
+
end
|
|
365
450
|
end
|
|
@@ -88,7 +88,7 @@ class PolymorphismTest < ActionDispatch::IntegrationTest
|
|
|
88
88
|
},
|
|
89
89
|
attributes: {
|
|
90
90
|
make: 'Mazda',
|
|
91
|
-
|
|
91
|
+
model: 'Miata MX5',
|
|
92
92
|
driveLayout: 'Front Engine RWD',
|
|
93
93
|
serialNumber: '32432adfsfdysua'
|
|
94
94
|
},
|
|
@@ -109,7 +109,7 @@ class PolymorphismTest < ActionDispatch::IntegrationTest
|
|
|
109
109
|
},
|
|
110
110
|
attributes: {
|
|
111
111
|
make: 'Chris-Craft',
|
|
112
|
-
|
|
112
|
+
model: 'Launch 20',
|
|
113
113
|
lengthAtWaterLine: '15.5ft',
|
|
114
114
|
serialNumber: '434253JJJSD'
|
|
115
115
|
},
|
|
@@ -1736,4 +1736,139 @@ class SerializerTest < ActionDispatch::IntegrationTest
|
|
|
1736
1736
|
serialized
|
|
1737
1737
|
)
|
|
1738
1738
|
end
|
|
1739
|
+
|
|
1740
|
+
def test_serialize_model_attr
|
|
1741
|
+
@make = Make.first
|
|
1742
|
+
serialized = JSONAPI::ResourceSerializer.new(
|
|
1743
|
+
MakeResource,
|
|
1744
|
+
).serialize_to_hash(MakeResource.new(@make, nil))
|
|
1745
|
+
|
|
1746
|
+
assert_hash_equals(
|
|
1747
|
+
{
|
|
1748
|
+
"model" => "A model attribute"
|
|
1749
|
+
},
|
|
1750
|
+
serialized[:data]["attributes"]
|
|
1751
|
+
)
|
|
1752
|
+
end
|
|
1753
|
+
|
|
1754
|
+
def test_confusingly_named_attrs
|
|
1755
|
+
@wp = WebPage.first
|
|
1756
|
+
serialized = JSONAPI::ResourceSerializer.new(
|
|
1757
|
+
WebPageResource,
|
|
1758
|
+
).serialize_to_hash(WebPageResource.new(@wp, nil))
|
|
1759
|
+
|
|
1760
|
+
assert_hash_equals(
|
|
1761
|
+
{
|
|
1762
|
+
:data=>{
|
|
1763
|
+
"id"=>"#{@wp.id}",
|
|
1764
|
+
"type"=>"webPages",
|
|
1765
|
+
"links"=>{
|
|
1766
|
+
:self=>"/webPages/#{@wp.id}"
|
|
1767
|
+
},
|
|
1768
|
+
"attributes"=>{
|
|
1769
|
+
"href"=>"http://example.com",
|
|
1770
|
+
"link"=>"http://link.example.com"
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
},
|
|
1774
|
+
serialized
|
|
1775
|
+
)
|
|
1776
|
+
end
|
|
1777
|
+
|
|
1778
|
+
def test_questionable_has_one
|
|
1779
|
+
# has_one
|
|
1780
|
+
out, err = capture_io do
|
|
1781
|
+
eval <<-CODE
|
|
1782
|
+
class ::Questionable < ActiveRecord::Base
|
|
1783
|
+
has_one :link
|
|
1784
|
+
has_one :href
|
|
1785
|
+
end
|
|
1786
|
+
class ::QuestionableResource < JSONAPI::Resource
|
|
1787
|
+
model_name '::Questionable'
|
|
1788
|
+
has_one :link
|
|
1789
|
+
has_one :href
|
|
1790
|
+
end
|
|
1791
|
+
cn = ::Questionable.new id: 1
|
|
1792
|
+
puts JSONAPI::ResourceSerializer.new(
|
|
1793
|
+
::QuestionableResource,
|
|
1794
|
+
).serialize_to_hash(::QuestionableResource.new(cn, nil))
|
|
1795
|
+
CODE
|
|
1796
|
+
end
|
|
1797
|
+
assert err.blank?
|
|
1798
|
+
assert_equal(
|
|
1799
|
+
{
|
|
1800
|
+
:data=>{
|
|
1801
|
+
"id"=>"1",
|
|
1802
|
+
"type"=>"questionables",
|
|
1803
|
+
"links"=>{
|
|
1804
|
+
:self=>"/questionables/1"
|
|
1805
|
+
},
|
|
1806
|
+
"relationships"=>{
|
|
1807
|
+
"link"=>{
|
|
1808
|
+
:links=>{
|
|
1809
|
+
:self=>"/questionables/1/relationships/link",
|
|
1810
|
+
:related=>"/questionables/1/link"
|
|
1811
|
+
}
|
|
1812
|
+
},
|
|
1813
|
+
"href"=>{
|
|
1814
|
+
:links=>{
|
|
1815
|
+
:self=>"/questionables/1/relationships/href",
|
|
1816
|
+
:related=>"/questionables/1/href"
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
}.to_s,
|
|
1822
|
+
out.strip
|
|
1823
|
+
)
|
|
1824
|
+
end
|
|
1825
|
+
|
|
1826
|
+
def test_questionable_has_many
|
|
1827
|
+
# has_one
|
|
1828
|
+
out, err = capture_io do
|
|
1829
|
+
eval <<-CODE
|
|
1830
|
+
class ::Questionable2 < ActiveRecord::Base
|
|
1831
|
+
self.table_name = 'questionables'
|
|
1832
|
+
has_many :links
|
|
1833
|
+
has_many :hrefs
|
|
1834
|
+
end
|
|
1835
|
+
class ::Questionable2Resource < JSONAPI::Resource
|
|
1836
|
+
model_name '::Questionable2'
|
|
1837
|
+
has_many :links
|
|
1838
|
+
has_many :hrefs
|
|
1839
|
+
end
|
|
1840
|
+
cn = ::Questionable2.new id: 1
|
|
1841
|
+
puts JSONAPI::ResourceSerializer.new(
|
|
1842
|
+
::Questionable2Resource,
|
|
1843
|
+
).serialize_to_hash(::Questionable2Resource.new(cn, nil))
|
|
1844
|
+
CODE
|
|
1845
|
+
end
|
|
1846
|
+
assert err.blank?
|
|
1847
|
+
assert_equal(
|
|
1848
|
+
{
|
|
1849
|
+
:data=>{
|
|
1850
|
+
"id"=>"1",
|
|
1851
|
+
"type"=>"questionable2s",
|
|
1852
|
+
"links"=>{
|
|
1853
|
+
:self=>"/questionable2s/1"
|
|
1854
|
+
},
|
|
1855
|
+
"relationships"=>{
|
|
1856
|
+
"links"=>{
|
|
1857
|
+
:links=>{
|
|
1858
|
+
:self=>"/questionable2s/1/relationships/links",
|
|
1859
|
+
:related=>"/questionable2s/1/links"
|
|
1860
|
+
}
|
|
1861
|
+
},
|
|
1862
|
+
"hrefs"=>{
|
|
1863
|
+
:links=>{
|
|
1864
|
+
:self=>"/questionable2s/1/relationships/hrefs",
|
|
1865
|
+
:related=>"/questionable2s/1/hrefs"
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
}.to_s,
|
|
1871
|
+
out.strip
|
|
1872
|
+
)
|
|
1873
|
+
end
|
|
1739
1874
|
end
|
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.6.
|
|
4
|
+
version: 0.6.1
|
|
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-10-
|
|
12
|
+
date: 2015-10-21 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: bundler
|
|
@@ -171,6 +171,7 @@ files:
|
|
|
171
171
|
- test/fixtures/hair_cuts.yml
|
|
172
172
|
- test/fixtures/iso_currencies.yml
|
|
173
173
|
- test/fixtures/line_items.yml
|
|
174
|
+
- test/fixtures/makes.yml
|
|
174
175
|
- test/fixtures/moons.yml
|
|
175
176
|
- test/fixtures/numeros_telefone.yml
|
|
176
177
|
- test/fixtures/order_flags.yml
|
|
@@ -186,6 +187,7 @@ files:
|
|
|
186
187
|
- test/fixtures/sections.yml
|
|
187
188
|
- test/fixtures/tags.yml
|
|
188
189
|
- test/fixtures/vehicles.yml
|
|
190
|
+
- test/fixtures/web_pages.yml
|
|
189
191
|
- test/helpers/assertions.rb
|
|
190
192
|
- test/helpers/functional_helpers.rb
|
|
191
193
|
- test/helpers/value_matchers.rb
|
|
@@ -248,6 +250,7 @@ test_files:
|
|
|
248
250
|
- test/fixtures/hair_cuts.yml
|
|
249
251
|
- test/fixtures/iso_currencies.yml
|
|
250
252
|
- test/fixtures/line_items.yml
|
|
253
|
+
- test/fixtures/makes.yml
|
|
251
254
|
- test/fixtures/moons.yml
|
|
252
255
|
- test/fixtures/numeros_telefone.yml
|
|
253
256
|
- test/fixtures/order_flags.yml
|
|
@@ -263,6 +266,7 @@ test_files:
|
|
|
263
266
|
- test/fixtures/sections.yml
|
|
264
267
|
- test/fixtures/tags.yml
|
|
265
268
|
- test/fixtures/vehicles.yml
|
|
269
|
+
- test/fixtures/web_pages.yml
|
|
266
270
|
- test/helpers/assertions.rb
|
|
267
271
|
- test/helpers/functional_helpers.rb
|
|
268
272
|
- test/helpers/value_matchers.rb
|