jsonapi-resources 0.5.0 → 0.5.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 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