jsonapi-resources 0.5.0 → 0.5.1

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: f3abcdf22a7970e7b4e51d624771006f875e857f
4
- data.tar.gz: 26703852c97b53b7a044f545a16256024d67522a
3
+ metadata.gz: d1860b6f54c5c18361eee885c58d9a44ca799223
4
+ data.tar.gz: 75520fb96150d1185d444c474f9b803e1efada5b
5
5
  SHA512:
6
- metadata.gz: fa580d57a12f10e6bd3732ab0b4c6b3818b8daa81ce995110f810d05e71ef16ed4f56b934ccd518c731aca4d617621070fa61e86363acd7fdd72167ffd58fa8e
7
- data.tar.gz: 96acb9c3f10654468c1639cd867e0658dc575318b3a452e463955ead6a64f885dbd5482a3b8a4dd803ae76b684560d839c67f507bd925b465f8f90811a43da41
6
+ metadata.gz: f335fd832a84998b16b4c10fb349c87fba4bfbc5e97166e3c7875c6d07ec46a6fe8453aba8d2297d12ab1a9c22ee28355695e009384a7bb3f2f41fd2ade7d8db
7
+ data.tar.gz: bf31f588b77dfa2c95d9ddcd6461ef984aa329c2c17641082662156b01a36c69aa6f51fcb2741f84886f0ccdee5c9d2f6108966cfd842db8bcae5509ebb44dd1
data/README.md CHANGED
@@ -102,16 +102,16 @@ class AuthorResource < JSONAPI::Resource
102
102
 
103
103
  def fetchable_fields
104
104
  if (context.current_user.guest)
105
- super(context) - [:email]
105
+ super - [:email]
106
106
  else
107
- super(context)
107
+ super
108
108
  end
109
109
  end
110
110
  end
111
111
  ```
112
112
 
113
- Context flows through from the controller and can be used to control the attributes based on the current user (or other
114
- value).
113
+ Context flows through from the controller to the resource and can be used to control the attributes based on the
114
+ current user (or other value).
115
115
 
116
116
  ##### Creatable and Updatable Attributes
117
117
 
@@ -262,7 +262,7 @@ end
262
262
 
263
263
  The relationship methods (`relationship`, `has_one`, and `has_many`) support the following options:
264
264
 
265
- * `class_name` - a string specifying the underlying class for the related resource
265
+ * `class_name` - a string specifying the underlying class for the related resource. Defaults to the `class_name` property on the underlying model.
266
266
  * `foreign_key` - the method on the resource used to fetch the related resource. Defaults to `<resource_name>_id` for has_one and `<resource_name>_ids` for has_many relationships.
267
267
  * `acts_as_set` - allows the entire set of related records to be replaced in one operation. Defaults to false if not set.
268
268
  * `polymorphic` - set to true to identify relationships that are polymorphic.
@@ -270,7 +270,7 @@ The relationship methods (`relationship`, `has_one`, and `has_many`) support the
270
270
 
271
271
  `to_one` relationships support the additional option:
272
272
  * `foreign_key_on` - defaults to `:self`. To indicate that the foreign key is on the related resource specify `:related`.
273
-
273
+
274
274
  Examples:
275
275
 
276
276
  ```ruby
@@ -338,7 +338,7 @@ class ContactResource < JSONAPI::Resource
338
338
  end
339
339
  ```
340
340
 
341
- Then a request could pass in a filter for example `http://example.com/contacts?filter[name_last]=Smith` and the system
341
+ Then a request could pass in a filter for example `http://example.com/contacts?filter[name_last]=Smith` and the system
342
342
  will find all people where the last name exactly matches Smith.
343
343
 
344
344
  ##### Default Filters
@@ -1276,12 +1276,13 @@ JSONAPI.configure do |config|
1276
1276
  # processing. If you want to use Rails' `rescue_from` macro to
1277
1277
  # catch this error and render a 403 status code, you should add
1278
1278
  # the `Pundit::NotAuthorizedError` to the `exception_class_whitelist`.
1279
+ # Subclasses of the whitelisted classes will also be whitelisted.
1279
1280
  config.exception_class_whitelist = []
1280
-
1281
+
1281
1282
  # Resource Linkage
1282
1283
  # Controls the serialization of resource linkage for non compound documents
1283
- # NOTE: always_include_has_many_linkage_data is not currently implemented
1284
- config.always_include_has_one_linkage_data = false
1284
+ # NOTE: always_include_to_many_linkage_data is not currently implemented
1285
+ config.always_include_to_one_linkage_data = false
1285
1286
  end
1286
1287
  ```
1287
1288
 
@@ -29,7 +29,7 @@ class ActiveRecordOperationsProcessor < JSONAPI::OperationsProcessor
29
29
  raise e
30
30
 
31
31
  rescue => e
32
- if JSONAPI.configuration.exception_class_whitelist.include?(e.class)
32
+ if JSONAPI.configuration.exception_class_whitelist.any? { |k| e.class.ancestors.include?(k) }
33
33
  raise e
34
34
  else
35
35
  internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
@@ -323,10 +323,11 @@ module JSONAPI
323
323
  end
324
324
 
325
325
  def pointer(attr_or_relationship_name)
326
+ formatted_attr_or_relationship_name = format_key(attr_or_relationship_name)
326
327
  if resource_relationships.include?(attr_or_relationship_name)
327
- "/data/relationships/#{attr_or_relationship_name}"
328
+ "/data/relationships/#{formatted_attr_or_relationship_name}"
328
329
  else
329
- "/data/attributes/#{attr_or_relationship_name}"
330
+ "/data/attributes/#{formatted_attr_or_relationship_name}"
330
331
  end
331
332
  end
332
333
  end
@@ -17,12 +17,12 @@ module JSONAPI
17
17
  attr_reader :filters, :include_directives, :sort_criteria, :paginator
18
18
 
19
19
  def initialize(resource_klass, options = {})
20
+ super(resource_klass, options)
20
21
  @filters = options[:filters]
21
22
  @include_directives = options[:include_directives]
22
23
  @sort_criteria = options.fetch(:sort_criteria, [])
23
24
  @paginator = options[:paginator]
24
25
  @transactional = false
25
- super(resource_klass, options)
26
26
  end
27
27
 
28
28
  def record_count
@@ -70,10 +70,10 @@ module JSONAPI
70
70
  attr_reader :id, :include_directives
71
71
 
72
72
  def initialize(resource_klass, options = {})
73
+ super(resource_klass, options)
73
74
  @id = options.fetch(:id)
74
75
  @include_directives = options[:include_directives]
75
76
  @transactional = false
76
- super(resource_klass, options)
77
77
  end
78
78
 
79
79
  def apply
@@ -94,10 +94,10 @@ module JSONAPI
94
94
  attr_reader :parent_key, :relationship_type
95
95
 
96
96
  def initialize(resource_klass, options = {})
97
+ super(resource_klass, options)
97
98
  @parent_key = options.fetch(:parent_key)
98
99
  @relationship_type = options.fetch(:relationship_type)
99
100
  @transactional = false
100
- super(resource_klass, options)
101
101
  end
102
102
 
103
103
  def apply
@@ -116,11 +116,11 @@ module JSONAPI
116
116
  attr_reader :source_klass, :source_id, :relationship_type
117
117
 
118
118
  def initialize(resource_klass, options = {})
119
+ super(resource_klass, options)
119
120
  @source_klass = options.fetch(:source_klass)
120
121
  @source_id = options.fetch(:source_id)
121
122
  @relationship_type = options.fetch(:relationship_type)
122
123
  @transactional = false
123
- super(resource_klass, options)
124
124
  end
125
125
 
126
126
  def apply
@@ -139,6 +139,7 @@ module JSONAPI
139
139
  attr_reader :source_klass, :source_id, :relationship_type, :filters, :sort_criteria, :paginator
140
140
 
141
141
  def initialize(resource_klass, options = {})
142
+ super(resource_klass, options)
142
143
  @source_klass = options.fetch(:source_klass)
143
144
  @source_id = options.fetch(:source_id)
144
145
  @relationship_type = options.fetch(:relationship_type)
@@ -146,7 +147,6 @@ module JSONAPI
146
147
  @sort_criteria = options[:sort_criteria]
147
148
  @paginator = options[:paginator]
148
149
  @transactional = false
149
- super(resource_klass, options)
150
150
  end
151
151
 
152
152
  def apply
@@ -168,8 +168,8 @@ module JSONAPI
168
168
  attr_reader :data
169
169
 
170
170
  def initialize(resource_klass, options = {})
171
- @data = options.fetch(:data)
172
171
  super(resource_klass, options)
172
+ @data = options.fetch(:data)
173
173
  end
174
174
 
175
175
  def apply
@@ -186,8 +186,8 @@ module JSONAPI
186
186
  class RemoveResourceOperation < Operation
187
187
  attr_reader :resource_id
188
188
  def initialize(resource_klass, options = {})
189
- @resource_id = options.fetch(:resource_id)
190
189
  super(resource_klass, options)
190
+ @resource_id = options.fetch(:resource_id)
191
191
  end
192
192
 
193
193
  def apply
@@ -205,9 +205,9 @@ module JSONAPI
205
205
  attr_reader :data, :resource_id
206
206
 
207
207
  def initialize(resource_klass, options = {})
208
+ super(resource_klass, options)
208
209
  @resource_id = options.fetch(:resource_id)
209
210
  @data = options.fetch(:data)
210
- super(resource_klass, options)
211
211
  end
212
212
 
213
213
  def apply
@@ -222,10 +222,10 @@ module JSONAPI
222
222
  attr_reader :resource_id, :relationship_type, :key_value
223
223
 
224
224
  def initialize(resource_klass, options = {})
225
+ super(resource_klass, options)
225
226
  @resource_id = options.fetch(:resource_id)
226
227
  @key_value = options.fetch(:key_value)
227
228
  @relationship_type = options.fetch(:relationship_type).to_sym
228
- super(resource_klass, options)
229
229
  end
230
230
 
231
231
  def apply
@@ -240,11 +240,11 @@ module JSONAPI
240
240
  attr_reader :resource_id, :relationship_type, :key_value, :key_type
241
241
 
242
242
  def initialize(resource_klass, options = {})
243
+ super(resource_klass, options)
243
244
  @resource_id = options.fetch(:resource_id)
244
245
  @key_value = options.fetch(:key_value)
245
246
  @key_type = options.fetch(:key_type)
246
247
  @relationship_type = options.fetch(:relationship_type).to_sym
247
- super(resource_klass, options)
248
248
  end
249
249
 
250
250
  def apply
@@ -259,10 +259,10 @@ module JSONAPI
259
259
  attr_reader :resource_id, :relationship_type, :data
260
260
 
261
261
  def initialize(resource_klass, options)
262
+ super(resource_klass, options)
262
263
  @resource_id = options.fetch(:resource_id)
263
264
  @data = options.fetch(:data)
264
265
  @relationship_type = options.fetch(:relationship_type).to_sym
265
- super(resource_klass, options)
266
266
  end
267
267
 
268
268
  def apply
@@ -277,10 +277,10 @@ module JSONAPI
277
277
  attr_reader :resource_id, :relationship_type, :data
278
278
 
279
279
  def initialize(resource_klass, options)
280
+ super(resource_klass, options)
280
281
  @resource_id = options.fetch(:resource_id)
281
282
  @data = options.fetch(:data)
282
283
  @relationship_type = options.fetch(:relationship_type).to_sym
283
- super(resource_klass, options)
284
284
  end
285
285
 
286
286
  def apply
@@ -295,10 +295,10 @@ module JSONAPI
295
295
  attr_reader :resource_id, :relationship_type, :associated_key
296
296
 
297
297
  def initialize(resource_klass, options)
298
+ super(resource_klass, options)
298
299
  @resource_id = options.fetch(:resource_id)
299
300
  @associated_key = options.fetch(:associated_key)
300
301
  @relationship_type = options.fetch(:relationship_type).to_sym
301
- super(resource_klass, options)
302
302
  end
303
303
 
304
304
  def apply
@@ -313,9 +313,9 @@ module JSONAPI
313
313
  attr_reader :resource_id, :relationship_type
314
314
 
315
315
  def initialize(resource_klass, options)
316
+ super(resource_klass, options)
316
317
  @resource_id = options.fetch(:resource_id)
317
318
  @relationship_type = options.fetch(:relationship_type).to_sym
318
- super(resource_klass, options)
319
319
  end
320
320
 
321
321
  def apply
@@ -33,10 +33,8 @@ module JSONAPI
33
33
  # Use transactions if more than one operation and if one of the operations can be transactional
34
34
  # Even if transactional transactions won't be used unless the derived OperationsProcessor supports them.
35
35
  @transactional = false
36
- if @operations.length > 1
37
- @operations.each do |operation|
38
- @transactional |= operation.transactional
39
- end
36
+ @operations.each do |operation|
37
+ @transactional |= operation.transactional
40
38
  end
41
39
 
42
40
  run_callbacks :operations do
@@ -604,7 +604,7 @@ module JSONAPI
604
604
  end
605
605
 
606
606
  def parse_remove_operation(params)
607
- keys = parse_key_array(params.permit(:id)[:id])
607
+ keys = parse_key_array(params.require(:id))
608
608
 
609
609
  keys.each do |key|
610
610
  @operations.push JSONAPI::RemoveResourceOperation.new(
@@ -613,8 +613,6 @@ module JSONAPI
613
613
  resource_id: key
614
614
  )
615
615
  end
616
- rescue ActionController::UnpermittedParameters => e
617
- @errors.concat(JSONAPI::Exceptions::ParametersNotAllowed.new(e.params).errors)
618
616
  rescue JSONAPI::Exceptions::Error => e
619
617
  @errors.concat(e.errors)
620
618
  end
@@ -596,7 +596,7 @@ module JSONAPI
596
596
  end
597
597
 
598
598
  def _as_parent_key
599
- @_as_parent_key ||= "#{_type.to_s.singularize}_#{_primary_key}"
599
+ @_as_parent_key ||= "#{_type.to_s.singularize}_id"
600
600
  end
601
601
 
602
602
  def _allowed_filters
@@ -621,7 +621,10 @@ module JSONAPI
621
621
  end
622
622
 
623
623
  def _model_class
624
- @model ||= _model_name.to_s.safe_constantize
624
+ return @model if @model
625
+ @model = _model_name.to_s.safe_constantize
626
+ fail NameError, "model could not be found for #{self.name}" if @model.nil?
627
+ @model
625
628
  end
626
629
 
627
630
  def _allowed_filter?(filter)
@@ -670,6 +673,15 @@ module JSONAPI
670
673
 
671
674
  attrs.each do |attr|
672
675
  check_reserved_relationship_name(attr)
676
+
677
+ # Initialize from an ActiveRecord model's properties
678
+ if _model_class < ActiveRecord::Base
679
+ model_association = _model_class.reflect_on_association(attr)
680
+ if model_association
681
+ options[:class_name] ||= model_association.class_name
682
+ end
683
+ end
684
+
673
685
  @_relationships[attr] = relationship = klass.new(attr, options)
674
686
 
675
687
  associated_records_method_name = case relationship
@@ -741,7 +753,7 @@ module JSONAPI
741
753
 
742
754
  sort_criteria = options.fetch(:sort_criteria, {})
743
755
  unless sort_criteria.nil? || sort_criteria.empty?
744
- order_options = self.class.construct_order_options(sort_criteria)
756
+ order_options = relationship.resource_klass.construct_order_options(sort_criteria)
745
757
  records = resource_klass.apply_sort(records, order_options)
746
758
  end
747
759
 
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Resources
3
- VERSION = '0.5.0'
3
+ VERSION = '0.5.1'
4
4
  end
5
5
  end
@@ -1427,13 +1427,6 @@ class PostsControllerTest < ActionController::TestCase
1427
1427
  assert_equal initial_count, Post.count
1428
1428
  end
1429
1429
 
1430
- def test_delete_extra_param
1431
- initial_count = Post.count
1432
- delete :destroy, {id: '4', asdfg: 'aaaa'}
1433
- assert_response :bad_request
1434
- assert_equal initial_count, Post.count
1435
- end
1436
-
1437
1430
  def test_show_to_one_relationship
1438
1431
  get :show_relationship, {post_id: '1', relationship: 'author'}
1439
1432
  assert_response :success
@@ -2159,11 +2152,8 @@ class Api::V1::PostsControllerTest < ActionController::TestCase
2159
2152
  end
2160
2153
 
2161
2154
  class FactsControllerTest < ActionController::TestCase
2162
- def setup
2163
- JSONAPI.configuration.json_key_format = :camelized_key
2164
- end
2165
-
2166
2155
  def test_type_formatting
2156
+ JSONAPI.configuration.json_key_format = :camelized_key
2167
2157
  get :show, {id: '1'}
2168
2158
  assert_response :success
2169
2159
  assert json_response['data'].is_a?(Hash)
@@ -2177,6 +2167,40 @@ class FactsControllerTest < ActionController::TestCase
2177
2167
  assert_equal 'abc', json_response['data']['attributes']['photo']
2178
2168
  assert_equal false, json_response['data']['attributes']['cool']
2179
2169
  end
2170
+
2171
+ def test_create_with_invalid_data
2172
+ JSONAPI.configuration.json_key_format = :dasherized_key
2173
+ set_content_type_header!
2174
+ post :create,
2175
+ {
2176
+ data: {
2177
+ type: 'facts',
2178
+ attributes: {
2179
+ bio: '',
2180
+ :"quality-rating" => '',
2181
+ :"spouse-name" => '',
2182
+ salary: 100000,
2183
+ :"date-time-joined" => '',
2184
+ birthday: '',
2185
+ bedtime: '',
2186
+ photo: 'abc',
2187
+ cool: false
2188
+ },
2189
+ relationships: {
2190
+ }
2191
+ }
2192
+ }
2193
+
2194
+ assert_response :unprocessable_entity
2195
+
2196
+ assert_equal "/data/attributes/spouse-name", json_response['errors'][0]['source']['pointer']
2197
+ assert_equal "can't be blank", json_response['errors'][0]['detail']
2198
+ assert_equal "spouse-name - can't be blank", json_response['errors'][0]['title']
2199
+
2200
+ assert_equal "/data/attributes/bio", json_response['errors'][1]['source']['pointer']
2201
+ assert_equal "can't be blank", json_response['errors'][1]['detail']
2202
+ assert_equal "bio - can't be blank", json_response['errors'][1]['title']
2203
+ end
2180
2204
  end
2181
2205
 
2182
2206
  class Api::V2::BooksControllerTest < ActionController::TestCase
@@ -2634,3 +2658,64 @@ class Api::V1::PlanetsControllerTest < ActionController::TestCase
2634
2658
  assert_match /Save failed or was cancelled/, json_response['errors'][0]['detail']
2635
2659
  end
2636
2660
  end
2661
+
2662
+ class Api::V1::MoonsControllerTest < ActionController::TestCase
2663
+ def test_get_related_resource
2664
+ get :get_related_resource, {crater_id: 'S56D', relationship: 'moon', source: "api/v1/craters"}
2665
+ assert_response :success
2666
+ assert_hash_equals json_response,
2667
+ {
2668
+ data: {
2669
+ id: "1",
2670
+ type: "moons",
2671
+ links: {self: "http://test.host/moons/1"},
2672
+ attributes: {name: "Titan", description: "Best known of the Saturn moons."},
2673
+ relationships: {
2674
+ planet: {links: {self: "http://test.host/moons/1/relationships/planet", related: "http://test.host/moons/1/planet"}},
2675
+ craters: {links: {self: "http://test.host/moons/1/relationships/craters", related: "http://test.host/moons/1/craters"}}}
2676
+ }
2677
+ }
2678
+
2679
+ end
2680
+ end
2681
+
2682
+ class Api::V1::CratersControllerTest < ActionController::TestCase
2683
+ def test_show_single
2684
+ get :show, {id: 'S56D'}
2685
+ assert_response :success
2686
+ assert json_response['data'].is_a?(Hash)
2687
+ assert_equal 'S56D', json_response['data']['attributes']['code']
2688
+ assert_equal 'Very large crater', json_response['data']['attributes']['description']
2689
+ assert_nil json_response['included']
2690
+ end
2691
+
2692
+ def test_get_related_resources
2693
+ get :get_related_resources, {moon_id: '1', relationship: 'craters', source: "api/v1/moons"}
2694
+ assert_response :success
2695
+ assert_hash_equals json_response,
2696
+ {
2697
+ data: [
2698
+ {id:"A4D3",
2699
+ type:"craters",
2700
+ links:{self: "http://test.host/craters/A4D3"},
2701
+ attributes:{code: "A4D3", description: "Small crater"},
2702
+ relationships:{moon: {links: {self: "http://test.host/craters/A4D3/relationships/moon", related: "http://test.host/craters/A4D3/moon"}}}
2703
+ },
2704
+ {id: "S56D",
2705
+ type: "craters",
2706
+ links:{self: "http://test.host/craters/S56D"},
2707
+ attributes:{code: "S56D", description: "Very large crater"},
2708
+ relationships:{moon: {links: {self: "http://test.host/craters/S56D/relationships/moon", related: "http://test.host/craters/S56D/moon"}}}
2709
+ }
2710
+ ]
2711
+ }
2712
+ end
2713
+
2714
+ def test_show_relationship
2715
+ get :show_relationship, {crater_id: 'S56D', relationship: 'moon'}
2716
+
2717
+ assert_response :success
2718
+ assert_equal "moons", json_response['data']['type']
2719
+ assert_equal "1", json_response['data']['id']
2720
+ end
2721
+ end
@@ -92,6 +92,12 @@ ActiveRecord::Schema.define do
92
92
  t.integer :planet_id
93
93
  end
94
94
 
95
+ create_table :craters, id: false, force: true do |t|
96
+ t.string :code
97
+ t.string :description
98
+ t.integer :moon_id
99
+ end
100
+
95
101
  create_table :preferences, force: true do |t|
96
102
  t.integer :person_id
97
103
  t.boolean :advanced_mode, default: false
@@ -248,6 +254,21 @@ end
248
254
  class Section < ActiveRecord::Base
249
255
  end
250
256
 
257
+ class HairCut < ActiveRecord::Base
258
+ end
259
+
260
+ class Property < ActiveRecord::Base
261
+ end
262
+
263
+ class Customer < ActiveRecord::Base
264
+ end
265
+
266
+ class BadlyNamedAttributes < ActiveRecord::Base
267
+ end
268
+
269
+ class Cat < ActiveRecord::Base
270
+ end
271
+
251
272
  class IsoCurrency < ActiveRecord::Base
252
273
  self.primary_key = :code
253
274
  # has_many :expense_entries, foreign_key: 'currency_code'
@@ -281,6 +302,14 @@ end
281
302
 
282
303
  class Moon < ActiveRecord::Base
283
304
  belongs_to :planet
305
+
306
+ has_many :craters
307
+ end
308
+
309
+ class Crater < ActiveRecord::Base
310
+ self.primary_key = :code
311
+
312
+ belongs_to :moon
284
313
  end
285
314
 
286
315
  class Preferences < ActiveRecord::Base
@@ -289,6 +318,7 @@ class Preferences < ActiveRecord::Base
289
318
  end
290
319
 
291
320
  class Fact < ActiveRecord::Base
321
+ validates :spouse_name, :bio, presence: true
292
322
  end
293
323
 
294
324
  class Like < ActiveRecord::Base
@@ -360,7 +390,7 @@ class BreedData
360
390
  end
361
391
  end
362
392
 
363
- class CustomerOrder < ActiveRecord::Base
393
+ class Customer < ActiveRecord::Base
364
394
  has_many :purchase_orders
365
395
  end
366
396
 
@@ -407,13 +437,6 @@ class Product < ActiveRecord::Base
407
437
  has_one :picture, as: :imageable
408
438
  end
409
439
 
410
- ### PORO Data - don't do this in a production app
411
- $breed_data = BreedData.new
412
- $breed_data.add(Breed.new(0, 'persian'))
413
- $breed_data.add(Breed.new(1, 'siamese'))
414
- $breed_data.add(Breed.new(2, 'sphinx'))
415
- $breed_data.add(Breed.new(3, 'to_delete'))
416
-
417
440
  ### OperationsProcessor
418
441
  class CountingActiveRecordOperationsProcessor < ActiveRecordOperationsProcessor
419
442
  after_find_operation do
@@ -429,7 +452,7 @@ class ErrorRaisingOperationsProcessor < ActiveRecordOperationsProcessor
429
452
  def process_operation(operation)
430
453
  mock_operation = Minitest::Mock.new
431
454
  mock_operation.expect(:apply, true) do
432
- raise PostsController::SpecialError
455
+ raise PostsController::SubSpecialError
433
456
  end
434
457
  super(mock_operation)
435
458
  end
@@ -445,6 +468,7 @@ end
445
468
  class PostsController < ActionController::Base
446
469
  include JSONAPI::ActsAsResourceController
447
470
  class SpecialError < StandardError; end
471
+ class SubSpecialError < PostsController::SpecialError; end
448
472
 
449
473
  # This is used to test that classes that are whitelisted are reraised by
450
474
  # the operations processor.
@@ -523,6 +547,9 @@ module Api
523
547
  class MoonsController < JSONAPI::ResourceController
524
548
  end
525
549
 
550
+ class CratersController < JSONAPI::ResourceController
551
+ end
552
+
526
553
  class LikesController < JSONAPI::ResourceController
527
554
  end
528
555
  end
@@ -860,13 +887,25 @@ class MoonResource < JSONAPI::Resource
860
887
  attribute :description
861
888
 
862
889
  has_one :planet
890
+ has_many :craters
891
+ end
892
+
893
+ class CraterResource < JSONAPI::Resource
894
+ attribute :code
895
+ attribute :description
896
+
897
+ has_one :moon
898
+
899
+ def self.verify_key(key, context = nil)
900
+ key && String(key)
901
+ end
863
902
  end
864
903
 
865
904
  class PreferencesResource < JSONAPI::Resource
866
905
  attribute :advanced_mode
867
906
 
868
- has_one :author, foreign_key: :person_id, class_name: 'Person'
869
- has_many :friends, class_name: 'Person'
907
+ has_one :author, foreign_key: :person_id
908
+ has_many :friends
870
909
 
871
910
  def self.find_by_key(key, options = {})
872
911
  new(Preferences.first)
@@ -930,7 +969,7 @@ module Api
930
969
  attribute :body
931
970
  attribute :subject
932
971
 
933
- has_one :writer, foreign_key: 'author_id'
972
+ has_one :writer, foreign_key: 'author_id', class_name: 'Writer'
934
973
  has_one :section
935
974
  has_many :comments, acts_as_set: false
936
975
 
@@ -951,6 +990,7 @@ module Api
951
990
  PlanetResource = PlanetResource.dup
952
991
  PlanetTypeResource = PlanetTypeResource.dup
953
992
  MoonResource = MoonResource.dup
993
+ CraterResource = CraterResource.dup
954
994
  PreferencesResource = PreferencesResource.dup
955
995
  EmployeeResource = EmployeeResource.dup
956
996
  FriendResource = FriendResource.dup
@@ -1214,28 +1254,9 @@ class BadlyNamedAttributesResource < JSONAPI::Resource
1214
1254
  end
1215
1255
  warn 'end testing Name Collisions'
1216
1256
 
1217
- ### PORO DATA
1218
- gas_giant = PlanetType.create(name: 'Gas Giant')
1219
- planetoid = PlanetType.create(name: 'Planetoid')
1220
- terrestrial = PlanetType.create(name: 'Terrestrial')
1221
- sulfuric = PlanetType.create(name: 'Sulfuric')
1222
- unknown = PlanetType.create(name: 'unknown')
1223
-
1224
- saturn = Planet.create(name: 'Satern',
1225
- description: 'Saturn is the sixth planet from the Sun and the second largest planet in the Solar System, after Jupiter.',
1226
- planet_type_id: planetoid.id)
1227
- titan = Moon.create(name:'Titan', description: 'Best known of the Saturn moons.', planet_id: saturn.id)
1228
- makemake = Planet.create(name: 'Makemake', description: 'A small planetoid in the Kuiperbelt.', planet_type_id: planetoid.id)
1229
- uranus = Planet.create(name: 'Uranus', description: 'Insert adolescent jokes here.', planet_type_id: gas_giant.id)
1230
- jupiter = Planet.create(name: 'Jupiter', description: 'A gas giant.', planet_type_id: gas_giant.id)
1231
- betax = Planet.create(name: 'Beta X', description: 'Newly discovered Planet X', planet_type_id: unknown.id)
1232
- betay = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Y', planet_type_id: unknown.id)
1233
- betaz = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Z', planet_type_id: unknown.id)
1234
- betaw = Planet.create(name: 'Beta W', description: 'Newly discovered Planet W')
1235
- Category.create(name: 'Category A', status: 'active')
1236
- Category.create(name: 'Category B', status: 'active')
1237
- Category.create(name: 'Category C', status: 'active')
1238
- Category.create(name: 'Category D', status: 'inactive')
1239
- Category.create(name: 'Category E', status: 'inactive')
1240
- Category.create(name: 'Category F', status: 'inactive')
1241
- Category.create(name: 'Category G', status: 'inactive')
1257
+ ### PORO Data - don't do this in a production app
1258
+ $breed_data = BreedData.new
1259
+ $breed_data.add(Breed.new(0, 'persian'))
1260
+ $breed_data.add(Breed.new(1, 'siamese'))
1261
+ $breed_data.add(Breed.new(2, 'sphinx'))
1262
+ $breed_data.add(Breed.new(3, 'to_delete'))
@@ -0,0 +1,35 @@
1
+ category_a:
2
+ id: 1
3
+ name: Category A
4
+ status: active
5
+
6
+ category_b:
7
+ id: 2
8
+ name: Category B
9
+ status: active
10
+
11
+ category_c:
12
+ id: 3
13
+ name: Category C
14
+ status: active
15
+
16
+ category_d:
17
+ id: 4
18
+ name: Category D
19
+ status: inactive
20
+
21
+ category_e:
22
+ id: 5
23
+ name: Category E
24
+ status: inactive
25
+
26
+ category_f:
27
+ id: 6
28
+ name: Category F
29
+ status: inactive
30
+
31
+ category_g:
32
+ id: 7
33
+ name: Category G
34
+ status: inactive
35
+
@@ -0,0 +1,9 @@
1
+ crater1:
2
+ code: S56D
3
+ description: Very large crater
4
+ moon_id: 1
5
+
6
+ crater2:
7
+ code: A4D3
8
+ description: Small crater
9
+ moon_id: 1
@@ -0,0 +1,6 @@
1
+ titan:
2
+ id: 1
3
+ name: Titan
4
+ description: Best known of the Saturn moons.
5
+ planet_id: 1
6
+
@@ -0,0 +1,19 @@
1
+ gas_giant:
2
+ id: 1
3
+ name: Gas Giant
4
+
5
+ planetoid:
6
+ id: 2
7
+ name: Planetoid
8
+
9
+ terrestrial:
10
+ id: 3
11
+ name: Terrestrial
12
+
13
+ sulfuric:
14
+ id: 4
15
+ name: Sulfuric
16
+
17
+ unknown:
18
+ id: 5
19
+ name: unknown
@@ -0,0 +1,47 @@
1
+ saturn:
2
+ id: 1
3
+ name: Satern
4
+ description: Saturn is the sixth planet from the Sun and the second largest planet in the Solar System, after Jupiter.
5
+ planet_type_id: 2
6
+
7
+ makemake:
8
+ id: 2
9
+ name: Makemake
10
+ description: A small planetoid in the Kuiperbelt.
11
+ planet_type_id: 2
12
+
13
+ uranus:
14
+ id: 3
15
+ name: Uranus
16
+ description: Insert adolescent jokes here.
17
+ planet_type_id: 1
18
+
19
+ jupiter:
20
+ id: 4
21
+ name: Jupiter
22
+ description: A gas giant.
23
+ planet_type_id: 1
24
+
25
+ betax:
26
+ id: 5
27
+ name: Beta X
28
+ description: Newly discovered Planet X
29
+ planet_type_id: 5
30
+
31
+ betay:
32
+ id: 6
33
+ name: Beta X
34
+ description: Newly discovered Planet Y
35
+ planet_type_id: 5
36
+
37
+ betaz:
38
+ id: 7
39
+ name: Beta X
40
+ description: Newly discovered Planet Z
41
+ planet_type_id: 5
42
+
43
+ betaw:
44
+ id: 8
45
+ name: Beta W
46
+ description: Newly discovered Planet W
47
+ planet_type_id:
data/test/test_helper.rb CHANGED
@@ -110,6 +110,7 @@ TestApp.routes.draw do
110
110
  jsonapi_resources :planets
111
111
  jsonapi_resources :planet_types
112
112
  jsonapi_resources :moons
113
+ jsonapi_resources :craters
113
114
  jsonapi_resources :preferences
114
115
  jsonapi_resources :facts
115
116
  jsonapi_resources :categories
@@ -130,6 +131,7 @@ TestApp.routes.draw do
130
131
  jsonapi_resources :planets
131
132
  jsonapi_resources :planet_types
132
133
  jsonapi_resources :moons
134
+ jsonapi_resources :craters
133
135
  jsonapi_resources :preferences
134
136
  jsonapi_resources :likes
135
137
  end
@@ -224,6 +226,14 @@ class Minitest::Test
224
226
  include Helpers::Assertions
225
227
  include Helpers::ValueMatchers
226
228
  include Helpers::FunctionalHelpers
229
+ include ActiveRecord::TestFixtures
230
+
231
+ def run_in_transaction?
232
+ true
233
+ end
234
+
235
+ self.fixture_path = "#{Rails.root}/fixtures"
236
+ fixtures :all
227
237
  end
228
238
 
229
239
  class ActiveSupport::TestCase
@@ -8,6 +8,9 @@ class ArticleResource < JSONAPI::Resource
8
8
  end
9
9
  end
10
10
 
11
+ class NoMatchResource < JSONAPI::Resource
12
+ end
13
+
11
14
  class CatResource < JSONAPI::Resource
12
15
  attribute :id
13
16
  attribute :name
@@ -52,6 +55,14 @@ class ResourceTest < ActiveSupport::TestCase
52
55
  assert_equal(PostResource._model_class, Post)
53
56
  end
54
57
 
58
+ def test_nil_model_class
59
+ error = assert_raises(NameError) { NoMatchResource._model_class }
60
+ assert_equal(
61
+ error.message,
62
+ "model could not be found for NoMatchResource"
63
+ )
64
+ end
65
+
55
66
  def test_model_alternate
56
67
  assert_equal(ArticleResource._model_class, Post)
57
68
  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.5.0
4
+ version: 0.5.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-07-16 00:00:00.000000000 Z
12
+ date: 2015-07-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -170,8 +170,10 @@ files:
170
170
  - test/fixtures/author_details.yml
171
171
  - test/fixtures/book_comments.yml
172
172
  - test/fixtures/books.yml
173
+ - test/fixtures/categories.yml
173
174
  - test/fixtures/comments.yml
174
175
  - test/fixtures/comments_tags.yml
176
+ - test/fixtures/craters.yml
175
177
  - test/fixtures/customers.yml
176
178
  - test/fixtures/documents.yml
177
179
  - test/fixtures/expense_entries.yml
@@ -179,10 +181,13 @@ files:
179
181
  - test/fixtures/hair_cuts.yml
180
182
  - test/fixtures/iso_currencies.yml
181
183
  - test/fixtures/line_items.yml
184
+ - test/fixtures/moons.yml
182
185
  - test/fixtures/numeros_telefone.yml
183
186
  - test/fixtures/order_flags.yml
184
187
  - test/fixtures/people.yml
185
188
  - test/fixtures/pictures.yml
189
+ - test/fixtures/planet_types.yml
190
+ - test/fixtures/planets.yml
186
191
  - test/fixtures/posts.yml
187
192
  - test/fixtures/posts_tags.yml
188
193
  - test/fixtures/preferences.yml
@@ -239,8 +244,10 @@ test_files:
239
244
  - test/fixtures/author_details.yml
240
245
  - test/fixtures/book_comments.yml
241
246
  - test/fixtures/books.yml
247
+ - test/fixtures/categories.yml
242
248
  - test/fixtures/comments.yml
243
249
  - test/fixtures/comments_tags.yml
250
+ - test/fixtures/craters.yml
244
251
  - test/fixtures/customers.yml
245
252
  - test/fixtures/documents.yml
246
253
  - test/fixtures/expense_entries.yml
@@ -248,10 +255,13 @@ test_files:
248
255
  - test/fixtures/hair_cuts.yml
249
256
  - test/fixtures/iso_currencies.yml
250
257
  - test/fixtures/line_items.yml
258
+ - test/fixtures/moons.yml
251
259
  - test/fixtures/numeros_telefone.yml
252
260
  - test/fixtures/order_flags.yml
253
261
  - test/fixtures/people.yml
254
262
  - test/fixtures/pictures.yml
263
+ - test/fixtures/planet_types.yml
264
+ - test/fixtures/planets.yml
255
265
  - test/fixtures/posts.yml
256
266
  - test/fixtures/posts_tags.yml
257
267
  - test/fixtures/preferences.yml