jsonapi-resources 0.0.13 → 0.0.14

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: 2d31c91126186e543683030f0b2c2a0fb513d64e
4
- data.tar.gz: 8bd319a9b582d306093f9cfaf82733f5edeb7aa1
3
+ metadata.gz: 6700d2a30e18dc6391ba4aa8bc0ecdd517e2fdfb
4
+ data.tar.gz: ad330dfe0d8fdc5da07d7ee40db08e892293296d
5
5
  SHA512:
6
- metadata.gz: d4b2634d12eba8207a651bdb60a42e82bb85136d7098feaaf70821ea58c8200636b8b4e480a423b8ab8e1af1f2f8837cb33fe307adf55843c6da770e4c02e7f9
7
- data.tar.gz: ebd5e529dd9662930ee305309cba83324325e090abdda8fcb7cf6a8cc204b437fde534d6de58d5815c5c1278efa9c527b4ea6ce3113940fcc651b00c5015bd37
6
+ metadata.gz: 893a1947cd78da813d77e69c92dafbaac07b50c8dab2ab495ebdf49da50c082f8123c99361cf95793e606dd4916d140401566a4465829bf137aa1f86144589db
7
+ data.tar.gz: d00fb87cc0c3a787d28fb68bc1d8072b6dc30143108dc3672770b19704430126511bf0aa73d2b86434546812ff6a4d194d710eb521a6f9d88840d8faeeef59d6
data/.travis.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
+ - 1.9.3
3
4
  - 2.0.0
4
- - 2.1.1
5
+ - 2.1
data/README.md CHANGED
@@ -260,42 +260,72 @@ end
260
260
 
261
261
  ##### Finders
262
262
 
263
- Basic finding by filters is supported by resources. However if you have more complex requirements for finding you can override the `find`, `find_by_key` and `find_by_keys` methods on the resource class.
263
+ Basic finding by filters is supported by resources. This is implemented in the `find`, `find_by_key` and `find_by_keys` finder methods. Currently this is implemented for ActiveRecord based resources. The finder methods rely on the `records` method to get an Arel relation. It is therefore possible to override `records` to affect the three find related methods.
264
264
 
265
- Here's an example that defers the `find` operation to a `current_user` set on the `context` option:
265
+ ###### Customizing base records for finder methods
266
266
 
267
- ```ruby
268
- class AuthorResource < JSONAPI::Resource
269
- attributes :id, :name
270
- model_name 'Person'
271
- has_many :posts
267
+ If you need to change the base records on which `find`, `find_by_key` and `find_by_keys` operate, you can override the `records` method on the resource class.
272
268
 
273
- filter :name
269
+ For example to allow a user to only retrieve his own posts you can do the following:
270
+
271
+ ```ruby
272
+ class PostResource < JSONAPI::Resource
273
+ attribute :id, :title, :body
274
274
 
275
- def self.find(attrs, options = {})
275
+ def self.records(options = {})
276
276
  context = options[:context]
277
- authors = context.current_user.find_authors(attrs)
277
+ context.current_user.posts
278
+ end
279
+ end
280
+ ```
278
281
 
279
- return authors.map do |author|
280
- self.new(author)
281
- end
282
+ ###### Applying Filters
283
+
284
+ The `apply_filter` method is called to apply each filter to the Arel relation. You may override this method to gain control over how the filters are applied to the Arel relation.
285
+
286
+ For example to change how a
287
+
288
+ ```ruby
289
+ def apply_filter(records, filter, value)
290
+ case filter
291
+ when :visibility
292
+ records.where('users.publicly_visible = ?', value == :public)
293
+ when :last_name, :first_name, :name
294
+ if value.is_a?(Array)
295
+ value.each do |val|
296
+ records = records.where(_model_class.arel_table[filter].matches(val))
297
+ end
298
+ return records
299
+ else
300
+ records.where(_model_class.arel_table[filter].matches(value))
301
+ end
302
+ else
303
+ return super(records, filter, value)
282
304
  end
283
305
  end
284
306
  ```
285
307
 
286
- ##### Customizing base records for finder methods
308
+ ###### Override finder methods
287
309
 
288
- If you need to change the base records on which `find`, `find_by_key` and `find_by_keys` operate, you can override the `records` method on the resource class.
310
+ Finally if you have more complex requirements for finding you can override the `find`, `find_by_key` and `find_by_keys` methods on the resource class.
289
311
 
290
- For example to allow a user to only retrieve his own posts you can do the following:
312
+ Here's an example that defers the `find` operation to a `current_user` set on the `context` option:
291
313
 
292
314
  ```ruby
293
- class PostResource < JSONAPI::Resource
294
- attribute :id, :title, :body
315
+ class AuthorResource < JSONAPI::Resource
316
+ attributes :id, :name
317
+ model_name 'Person'
318
+ has_many :posts
295
319
 
296
- def self.records(options = {})
320
+ filter :name
321
+
322
+ def self.find(filters, options = {})
297
323
  context = options[:context]
298
- context.current_user.posts
324
+ authors = context.current_user.find_authors(filters)
325
+
326
+ return authors.map do |author|
327
+ self.new(author)
328
+ end
299
329
  end
300
330
  end
301
331
  ```
@@ -97,12 +97,7 @@ end
97
97
  class DefaultValueFormatter < JSONAPI::ValueFormatter
98
98
  class << self
99
99
  def format(raw_value, context)
100
- case raw_value
101
- when String, Integer
102
- return raw_value
103
- else
104
- return raw_value.to_s
105
- end
100
+ raw_value
106
101
  end
107
102
  end
108
103
  end
@@ -20,7 +20,7 @@ module JSONAPI
20
20
  end
21
21
 
22
22
  def setup(params)
23
- @resource_klass ||= self.class.resource_for(params[:controller]) if params[:controller]
23
+ @resource_klass ||= self.class.resource_for(params[:controller].split('/').last) if params[:controller]
24
24
 
25
25
  unless params.nil?
26
26
  case params[:action]
@@ -76,10 +76,14 @@ module JSONAPI
76
76
  fields.each do |type, values|
77
77
  underscored_type = unformat_key(type)
78
78
  fields[type] = []
79
- type_resource = self.class.resource_for(underscored_type)
80
- if type_resource.nil? || !(@resource_klass._type == underscored_type ||
81
- @resource_klass._has_association?(underscored_type))
79
+ begin
80
+ type_resource = self.class.resource_for(underscored_type)
81
+ rescue NameError
82
82
  @errors.concat(JSONAPI::Exceptions::InvalidResource.new(type).errors)
83
+ end
84
+ if type_resource.nil? || !(@resource_klass._type == underscored_type ||
85
+ @resource_klass._has_association?(underscored_type))
86
+ @errors.concat(JSONAPI::Exceptions::InvalidResource.new(type).errors)
83
87
  else
84
88
  unless values.nil?
85
89
  valid_fields = type_resource.fields.collect {|key| format_key(key)}
@@ -217,29 +217,34 @@ module JSONAPI
217
217
  _associations.keys | _attributes.keys
218
218
  end
219
219
 
220
+ def apply_filter(records, filter, value)
221
+ records.where(filter => value)
222
+ end
223
+
220
224
  # Override this method if you have more complex requirements than this basic find method provides
221
225
  def find(filters, options = {})
222
226
  context = options[:context]
223
227
  sort_params = options.fetch(:sort_params) { [] }
224
228
  includes = []
225
- where_filters = {}
229
+
230
+ records = records(options)
226
231
 
227
232
  filters.each do |filter, value|
228
233
  if _associations.include?(filter)
229
234
  if _associations[filter].is_a?(JSONAPI::Association::HasMany)
230
235
  includes.push(filter)
231
- where_filters["#{filter}.#{_associations[filter].primary_key}"] = value
236
+ records = apply_filter(records, "#{filter}.#{_associations[filter].primary_key}", value)
232
237
  else
233
- where_filters["#{_associations[filter].foreign_key}"] = value
238
+ records = apply_filter(records, "#{_associations[filter].foreign_key}", value)
234
239
  end
235
240
  else
236
- where_filters[filter] = value
241
+ records = apply_filter(records, filter, value)
237
242
  end
238
243
  end
239
244
 
240
245
  resources = []
241
246
  order_options = construct_order_options(sort_params)
242
- records(options).where(where_filters).order(order_options).includes(includes).each do |model|
247
+ records.order(order_options).includes(includes).each do |model|
243
248
  resources.push self.new(model, context)
244
249
  end
245
250
 
@@ -260,7 +265,7 @@ module JSONAPI
260
265
  _models = records(options).where({_primary_key => keys})
261
266
 
262
267
  unless _models.length == keys.length
263
- key = (keys - _models.pluck(:id).map(&:to_s)).first
268
+ key = (keys - _models.pluck(_primary_key).map(&:to_s)).first
264
269
  raise JSONAPI::Exceptions::RecordNotFound.new(key)
265
270
  end
266
271
 
@@ -11,15 +11,19 @@ module JSONAPI
11
11
  resource_name = JSONAPI::Resource._resource_name_from_type(type)
12
12
  Object.const_get resource_name if resource_name
13
13
  rescue NameError
14
- nil
14
+ raise NameError, "JSONAPI: Could not find resource '#{type}'. (Class #{resource_name} not found)"
15
15
  end
16
16
  else
17
17
  def resource_for(type)
18
18
  resource_name = JSONAPI::Resource._resource_name_from_type(type)
19
- resource_name.safe_constantize if resource_name
19
+ resource = resource_name.safe_constantize if resource_name
20
+ if resource.nil?
21
+ raise NameError, "JSONAPI: Could not find resource '#{type}'. (Class #{resource_name} not found)"
22
+ end
23
+ resource
20
24
  end
21
25
  end
22
26
  # :nocov:
23
27
  end
24
28
  end
25
- end
29
+ end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Resources
3
- VERSION = "0.0.13"
3
+ VERSION = "0.0.14"
4
4
  end
5
5
  end
@@ -1106,7 +1106,7 @@ class ExpenseEntriesControllerTest < ActionController::TestCase
1106
1106
  assert json_response['expense_entries'].is_a?(Hash)
1107
1107
  assert_equal 3, json_response['expense_entries']['links']['employee']
1108
1108
  assert_equal 'USD', json_response['expense_entries']['links']['iso_currency']
1109
- assert_equal '50.58', json_response['expense_entries']['cost']
1109
+ assert_equal 50.58, json_response['expense_entries']['cost']
1110
1110
 
1111
1111
  delete :destroy, {id: json_response['expense_entries']['id']}
1112
1112
  assert_response :no_content
@@ -1133,7 +1133,7 @@ class ExpenseEntriesControllerTest < ActionController::TestCase
1133
1133
  assert json_response['expenseEntries'].is_a?(Hash)
1134
1134
  assert_equal 3, json_response['expenseEntries']['links']['employee']
1135
1135
  assert_equal 'USD', json_response['expenseEntries']['links']['isoCurrency']
1136
- assert_equal '50.58', json_response['expenseEntries']['cost']
1136
+ assert_equal 50.58, json_response['expenseEntries']['cost']
1137
1137
 
1138
1138
  delete :destroy, {id: json_response['expenseEntries']['id']}
1139
1139
  assert_response :no_content
@@ -1160,7 +1160,7 @@ class ExpenseEntriesControllerTest < ActionController::TestCase
1160
1160
  assert json_response['expense-entries'].is_a?(Hash)
1161
1161
  assert_equal 3, json_response['expense-entries']['links']['employee']
1162
1162
  assert_equal 'USD', json_response['expense-entries']['links']['iso-currency']
1163
- assert_equal '50.58', json_response['expense-entries']['cost']
1163
+ assert_equal 50.58, json_response['expense-entries']['cost']
1164
1164
 
1165
1165
  delete :destroy, {id: json_response['expense-entries']['id']}
1166
1166
  assert_response :no_content
@@ -1466,3 +1466,21 @@ class Api::V2::PreferencesControllerTest < ActionController::TestCase
1466
1466
  assert_response :success
1467
1467
  end
1468
1468
  end
1469
+
1470
+ class FactsControllerTest < ActionController::TestCase
1471
+ def test_type_formatting
1472
+ get :show, {id: '1'}
1473
+ assert_response :success
1474
+ assert json_response['facts'].is_a?(Hash)
1475
+ assert_equal 'Jane Author', json_response['facts']['spouseName']
1476
+ assert_equal 'First man to run across Antartica.', json_response['facts']['bio']
1477
+ assert_equal 23.89/45.6, json_response['facts']['qualityRating']
1478
+ assert_equal 47000.56, json_response['facts']['salary']
1479
+ assert_equal '2013-08-07T20:25:00.000Z', json_response['facts']['dateTimeJoined']
1480
+ assert_equal '1965-06-30', json_response['facts']['birthday']
1481
+ assert_equal '2000-01-01T20:00:00Z', json_response['facts']['bedtime']
1482
+ assert_equal 'abc', json_response['facts']['photo']
1483
+ assert_equal false, json_response['facts']['cool']
1484
+ end
1485
+ end
1486
+
@@ -92,6 +92,19 @@ ActiveRecord::Schema.define do
92
92
  t.integer :person_id
93
93
  t.boolean :advanced_mode, default: false
94
94
  end
95
+
96
+ create_table :facts, force: true do |t|
97
+ t.integer :person_id
98
+ t.string :spouse_name
99
+ t.text :bio
100
+ t.float :quality_rating
101
+ t.decimal :salary, :precision => 12, :scale => 2
102
+ t.datetime :date_time_joined
103
+ t.date :birthday
104
+ t.time :bedtime
105
+ t.binary :photo, limit: 1.kilobyte
106
+ t.boolean :cool
107
+ end
95
108
  end
96
109
 
97
110
  ### MODELS
@@ -160,6 +173,9 @@ class Preferences < ActiveRecord::Base
160
173
  has_many :friends, class_name: 'Person'
161
174
  end
162
175
 
176
+ class Fact < ActiveRecord::Base
177
+ end
178
+
163
179
  class Breed
164
180
 
165
181
  def initialize(id = nil, name = nil)
@@ -236,6 +252,9 @@ end
236
252
  class BreedsController < JSONAPI::ResourceController
237
253
  end
238
254
 
255
+ class FactsController < JSONAPI::ResourceController
256
+ end
257
+
239
258
  ### CONTROLLERS
240
259
  module Api
241
260
  module V1
@@ -455,7 +474,7 @@ class BreedResource < JSONAPI::Resource
455
474
  # This is unneeded, just here for testing
456
475
  routing_options :param => :id
457
476
 
458
- def self.find(attrs, options = {})
477
+ def self.find(filters, options = {})
459
478
  breeds = []
460
479
  $breed_data.breeds.values.each do |breed|
461
480
  breeds.push(BreedResource.new(breed, options[:context]))
@@ -509,11 +528,24 @@ class PreferencesResource < JSONAPI::Resource
509
528
  has_one :author, foreign_key: :person_id
510
529
  has_many :friends
511
530
 
512
- def self.find_by_key(key, context: nil)
531
+ def self.find_by_key(key, options = {})
513
532
  new(Preferences.first)
514
533
  end
515
534
  end
516
535
 
536
+ class FactResource < JSONAPI::Resource
537
+ attribute :id
538
+ attribute :spouse_name
539
+ attribute :bio
540
+ attribute :quality_rating
541
+ attribute :salary
542
+ attribute :date_time_joined
543
+ attribute :birthday
544
+ attribute :bedtime
545
+ attribute :photo
546
+ attribute :cool
547
+ end
548
+
517
549
  warn 'start testing Name Collisions'
518
550
  # The name collisions only emmit warnings. Exceptions would change the flow of the tests
519
551
 
@@ -685,3 +717,14 @@ betaz = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Z',
685
717
  betaw = Planet.create(name: 'Beta W', description: 'Newly discovered Planet W')
686
718
 
687
719
  preference = Preferences.create
720
+
721
+ fact = Fact.create(spouse_name: 'Jane Author',
722
+ bio: 'First man to run across Antartica.',
723
+ quality_rating: 23.89/45.6,
724
+ salary: BigDecimal('47000.56'),
725
+ date_time_joined: DateTime.parse('2013-08-07 20:25:00 UTC +00:00'),
726
+ birthday: Date.parse('1965-06-30'),
727
+ bedtime: Time.parse('2000-01-01 20:00:00 UTC +00:00'),
728
+ photo: "abc",
729
+ cool: false
730
+ )
data/test/test_helper.rb CHANGED
@@ -31,6 +31,8 @@ class TestApp < Rails::Application
31
31
  config.session_store :cookie_store, key: 'session'
32
32
  config.secret_key_base = 'secret'
33
33
 
34
+ ActiveSupport::JSON::Encoding.encode_big_decimal_as_string = false
35
+
34
36
  #Raise errors on unsupported parameters
35
37
  config.action_controller.action_on_unpermitted_parameters = :raise
36
38
  end
@@ -53,6 +55,7 @@ TestApp.routes.draw do
53
55
  jsonapi_resources :planet_types
54
56
  jsonapi_resources :moons
55
57
  jsonapi_resources :preferences
58
+ jsonapi_resources :facts
56
59
 
57
60
  namespace :api do
58
61
  namespace :v1 do
@@ -505,7 +505,7 @@ class SerializerTest < MiniTest::Unit::TestCase
505
505
  expenseEntries: {
506
506
  id: 1,
507
507
  transactionDate: '04/15/2014',
508
- cost: '12.05',
508
+ cost: 12.05,
509
509
  links: {
510
510
  isoCurrency: 'USD',
511
511
  employee: 3
@@ -602,4 +602,46 @@ class SerializerTest < MiniTest::Unit::TestCase
602
602
  assert_match /\"planetType\":null/, json
603
603
  assert_match /\"moons\":\[\]/, json
604
604
  end
605
+
606
+ def test_serializer_booleans
607
+ JSONAPI.configuration.json_key_format = :underscored_key
608
+
609
+ preferences = PreferencesResource.new(Preferences.find(1))
610
+
611
+ assert_hash_equals(
612
+ {
613
+ preferences: {
614
+ id: 1,
615
+ advanced_mode: false,
616
+ links: {
617
+ author: nil,
618
+ friends: []
619
+ }
620
+ }
621
+ },
622
+ JSONAPI::ResourceSerializer.new(PreferencesResource).serialize_to_hash(preferences))
623
+ end
624
+
625
+ def test_serializer_data_types
626
+ JSONAPI.configuration.json_key_format = :underscored_key
627
+
628
+ facts = FactResource.new(Fact.find(1))
629
+
630
+ assert_hash_equals(
631
+ {
632
+ facts: {
633
+ id: 1,
634
+ spouse_name: 'Jane Author',
635
+ bio: 'First man to run across Antartica.',
636
+ quality_rating: 23.89/45.6,
637
+ salary: BigDecimal('47000.56', 30),
638
+ date_time_joined: DateTime.parse('2013-08-07 20:25:00 UTC +00:00'),
639
+ birthday: Date.parse('1965-06-30'),
640
+ bedtime: Time.parse('2000-01-01 20:00:00 UTC +00:00'), #DB seems to set the date to 2001-01-01 for time types
641
+ photo: "abc",
642
+ cool: false
643
+ }
644
+ },
645
+ JSONAPI::ResourceSerializer.new(FactResource).serialize_to_hash(facts))
646
+ end
605
647
  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.0.13
4
+ version: 0.0.14
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: 2014-12-06 00:00:00.000000000 Z
12
+ date: 2015-01-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler